home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / sbin / wifi-radar < prev    next >
Text File  |  2006-01-20  |  71KB  |  1,798 lines

  1. #!/usr/bin/python -OO
  2. #    wifi_radar.py
  3. #    A wireless profile manager for X1000 Linux
  4. #    http://x1000.bitbuilder.com
  5. #
  6. #    Ahmad Baitalmal <ahmad@baitalmal.com>
  7. #    This software is under the GPL license
  8. #
  9. #    http://www.bitbuilder.com/wifi_radar
  10. #    http://svn.bitbuilder.com
  11. #
  12. #    See AUTHORS file for more contributors.
  13. #
  14. import time, os, signal, sys, re, ConfigParser, thread
  15. WIFI_RADAR_VERSION = "1.9.4"
  16. ####################################################################################################
  17. # Defaults, these may get overridden by values found in the conf file
  18. # The interface you use
  19. INTERFACE        = "eth1"
  20. # How long should the scan last?
  21. SCAN_TIMEOUT    = "5"
  22. # Should I speak up when connecting to a network? (If you have a speach command)
  23. SPEAK_UP        = False
  24. # You may set this to true for cards that require a "commit" command with iwconfig
  25. COMMIT_REQUIRED    = False
  26. # You may set this to true for cards that require the interface to be brought up first
  27. IFUP_REQUIRED    = False
  28. # Where the conf file is could be different for your distro.
  29. CONF_FILE        = "/etc/wifi-radar.conf"
  30. IWLIST_COMMAND    = "iwlist"
  31. IWCONFIG_COMMAND= "iwconfig"
  32. IFCONFIG_COMMAND= "ifconfig"
  33. ROUTE_COMMAND    = "route"
  34. # X1000 Linux has a say command (text to speach) to accounce connecting to networks.
  35. # Set the SPEAK_UP to false if you do not have or want this.
  36. SAY_COMMAND        = "say"
  37. # DHCP FUN :)
  38. DHCP_TIMEOUT    = 30
  39. # For distros that use dhcpcd
  40. DHCP_COMMAND    = "dhcpcd"
  41. DHCP_KILL_COMMAND="dhcpcd -k"
  42. DHCP_ARGS        = "-S -t %s -h `hostname` " % DHCP_TIMEOUT
  43. DHCP_PIDFILE    = "/var/run/dhcpcd-%s.pid" % INTERFACE
  44. # For distros that use dhclient
  45. # DHCP_COMMAND    = "/sbin/dhclient" % DHCP_TIMEOUT
  46. # DHCP_KILL_COMMAND=""
  47. # DHCP_ARGS        = "-1 -q -pf " + DHCP_PIDFILE
  48. # DHCP_PIDFILE    = "/var/run/dhcpcd-wifi.pid"
  49. # WPA_SUPPLICANT
  50. WPA_SUPPLICANT_COMMAND    = "/usr/sbin/wpa_supplicant"
  51. WPA_SUPPLICANT_KILL_COMMAND=""
  52. WPA_SUPPLICANT_CONF="/etc/wpa_supplicant/wpa_supplicant.conf"
  53. WPA_DRIVER="ipw"
  54. WPA_SUPPLICANT_PIDFILE    = "/var/run/wpa_supplicant.pid"
  55. WPA_SUPPLICANT_ARGS    = "-B -i %s -c " + WPA_SUPPLICANT_CONF + " -D %s -P " + WPA_SUPPLICANT_PIDFILE
  56.  
  57. #####################################
  58. # Labels
  59. USE_DHCP_LABEL    = "Automatic network configuration (DHCP)"
  60. USE_IP_LABEL    = "Manual network configuration"
  61. WIFI_SET_LABEL    = "WiFi Options"
  62. POSTPRE_LABEL    = "Connection Commands"
  63. USE_WPA_LABEL    = "Use WPA"
  64. NO_WPA_LABEL    = "No WPA"
  65. WIFI_MODES        = [ '', 'auto', 'Managed', 'Ad-Hoc', 'Master', 'Repeater', 'Secondary', 'Monitor' ]
  66. WIFI_SECURITY    = [ '', 'open', 'restricted' ]
  67. WIFI_CHANNELS    = [ '', 'auto', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14' ]
  68. ####################################################################################################
  69.  
  70. ####################################################################################################
  71. ####################################################################################################
  72. # Scan for a limited time, return ap names found
  73. def scanning_thread( lock = None ):
  74.     global access_points
  75.     global main_radar_window
  76.     global exit_flag
  77.     global current_ip
  78.     global current_ssid
  79.     # Setup our essid pattern matcher
  80.     essid_pattern        = re.compile( "ESSID\s*(:|=)\s*\"([^\"]+)\"", re.I | re.M  | re.S )
  81.     protocol_pattern    = re.compile( "Protocol\s*(:|=)\s*IEEE 802.11\s*([abg]+)", re.I | re.M  | re.S )
  82.     mode_pattern        = re.compile( "Mode\s*(:|=)\s*([^\n]+)", re.I | re.M  | re.S )
  83.     enckey_pattern        = re.compile( "Encryption key\s*(:|=)\s*(on|off)", re.I | re.M  | re.S )
  84.     signal_pattern        = re.compile( "Signal level\s*(:|=)\s*-?([0-9]+)", re.I | re.M  | re.S )
  85.     # Access points we find will be added to the access_points dictionary
  86.     scan_command         = "%s %s scan" % ( IWLIST_COMMAND, INTERFACE )
  87.     # Some cards neet to have the interface up to scan
  88.     if IFUP_REQUIRED:
  89.         os.spawnlp( os.P_WAIT, IFCONFIG_COMMAND, IFCONFIG_COMMAND, INTERFACE, "up" )
  90.     trial = 0
  91.     while True:
  92.         # reset the signal strengths
  93.         if __debug__:
  94.             print ".",
  95.         # Read data
  96.         f = os.popen( scan_command, "r" )
  97.         scandata = f.read()
  98.         f.close()
  99.         # get the current ip
  100.         curr_ip = get_current_ip()
  101.         if __debug__:
  102.             print "Got current IP ", curr_ip
  103.         if curr_ip:
  104.             current_ip        = curr_ip
  105.         else:
  106.             current_ip        = 'None'
  107.         # get the current ssid
  108.         curr_ssid = get_current_ssid()
  109.         if __debug__:
  110.             print "Got current SSID ", curr_ssid
  111.         if curr_ssid:
  112.             current_ssid    = curr_ssid
  113.         else:
  114.             current_ssid    = 'None'
  115.         # we may not be running in a thread
  116.         try:
  117.             lock.acquire()
  118.         except:
  119.             trial = trial + 1
  120.             if trial > int( SCAN_TIMEOUT ):
  121.                 return
  122.         if exit_flag:
  123.             if __debug__:
  124.                 print "Ending scan"
  125.             thread.exit()
  126.             return
  127.         for ap in access_points:
  128.             access_points[ ap ]['signal'] = '0'
  129.         # split the scan data based on the address
  130.         hits = scandata.split( '- Address:' )
  131.         for hit in hits:
  132.             foundvalues = False
  133.             apname        = ''
  134.             protocol    = 'b'
  135.             mode        = ''
  136.             encrypted    = 'off'
  137.             signal        = '0'
  138.             m = essid_pattern.search( hit )
  139.             if m:
  140.                 # we found an ssid
  141.                 foundvalues = True
  142.                 apname = m.groups()[1]
  143.                 m = protocol_pattern.search( hit )
  144.                 if m:
  145.                     protocol = m.groups()[1]
  146.                 m = mode_pattern.search( hit )
  147.                 if m:
  148.                     mode = m.groups()[1]
  149.                 m = enckey_pattern.search( hit )
  150.                 if m:
  151.                     encrypted = m.groups()[1]
  152.                 m = signal_pattern.search( hit )
  153.                 if m:
  154.                     signal = m.groups()[1]
  155.                 # Set the values we found
  156.                 if access_points.has_key( apname ):
  157.                     # We know this ssid, make it available
  158.                     access_points[ apname ]['available'] = True
  159.                 else:
  160.                     # Add it to the available networks
  161.                     ap = {}
  162.                     ap['known']        = False
  163.                     ap['available']    = True
  164.                     access_points[ apname ] = ap
  165.                 access_points[ apname ]['protocol']    = protocol
  166.                 access_points[ apname ]['mode']        = mode
  167.                 access_points[ apname ]['encrypted']= ( encrypted == 'on' )
  168.                 access_points[ apname ]['signal']     = signal
  169.         try: lock.release()
  170.         except:    pass
  171.         time.sleep( 0.5 )
  172.     return
  173.  
  174. # Connects to the first matching network
  175. def connect_to_preferred():
  176.     global access_points
  177.     global auto_profile_order
  178.     found_one = False
  179.     for ssid in auto_profile_order:
  180.         ssid = ssid.strip()
  181.         if     access_points.has_key( ssid )    \
  182.             and    access_points[ ssid ]['known'] \
  183.             and access_points[ ssid ]['available']:
  184.             found_one = True
  185.             connect_to_network( ssid, None )
  186.             break
  187.     if not found_one:
  188.         say( "No preferred network found" )
  189.         if __debug__:
  190.             print "   No preferred network found"
  191.             print access_points
  192.  
  193. def get_current_ip():
  194.     """Returns the current IP if any by calling ifconfig"""
  195.     ifconfig_info = os.popen( IFCONFIG_COMMAND + " " + INTERFACE, 'r' )
  196.     # Be careful to the language (inet adr: in French for example)
  197.     ip_re = re.compile(r'inet ad?dr:([^.]*\.[^.]*\.[^.]*\.[0-9]*)')
  198.     for line in ifconfig_info:
  199.         if ip_re.search( line ):
  200.             return ip_re.search( line ).group(1)
  201.     return False
  202.  
  203. def get_current_ssid():
  204.     """Returns the current SSID if any by calling iwconfig"""
  205.     ifconfig_info = os.popen( IWCONFIG_COMMAND + " " + INTERFACE, 'r' )
  206.     # Be careful to the language (inet adr: in French for example)
  207.     essid_re = re.compile(r'ESSID\s*(:|=)\s*"([^"]*)"')
  208.     for line in ifconfig_info:
  209.         if essid_re.search( line ):
  210.             return essid_re.search( line ).group(2)
  211.     return False
  212.  
  213. def    connect_to_network( essid, status_win ):
  214.     msg = "Connecting to the %s network" % essid
  215.     say( msg )
  216.     if __debug__:
  217.         print "   %s" % msg
  218.     profile = get_profile_from_conf_file( essid )
  219.     if not profile:
  220.         if __debug__:
  221.             print "Unknown SSID"
  222.         say( "Unknown SSID" )
  223.         return
  224.     # ready to dance
  225.     # Let's run the prescript
  226.     prescript = profile['prescript']
  227.     if prescript.strip() != '':
  228.         # got something to execute
  229.         if __debug__:
  230.             print "executing prescript:", prescript
  231.         os.system( prescript )
  232.     # Some cards neet to have the interface up
  233.     if IFUP_REQUIRED:
  234.         os.spawnlp( os.P_WAIT, IFCONFIG_COMMAND, IFCONFIG_COMMAND, INTERFACE, "up" )
  235.     iwconfig_args = [ INTERFACE ]
  236.     # Let's start with the ssid
  237.     if __debug__:
  238.         print "Setting essid ", essid
  239.     iwconfig_args.append( 'essid' )
  240.     iwconfig_args.append( '"%s"' % essid )
  241.     iwconfig_args.append( 'nick' )
  242.     iwconfig_args.append( '"%s"' % essid )
  243.     #os.spawnlp( os.P_WAIT, IWCONFIG_COMMAND, IWCONFIG_COMMAND, INTERFACE, 'essid', "%s" % essid )
  244.     # Now we do the key
  245.     key     = profile['key']
  246.     security= profile['security']
  247.     if  key == '':
  248.         key     = 'off'
  249.     else:
  250.         key = "%s %s" % ( profile['security'], profile['key'], )
  251.     if __debug__:
  252.         print "Setting key ", key
  253.     #os.spawnlp( os.P_WAIT, IWCONFIG_COMMAND, IWCONFIG_COMMAND, INTERFACE, 'key', key )
  254.     iwconfig_args.append( 'key' )
  255.     iwconfig_args.append( key )
  256.     # Now, the mode
  257.     mode    = profile['mode']
  258.     if mode != '':
  259.         if __debug__:
  260.             print "Setting mode ", mode
  261.         #os.spawnlp( os.P_WAIT, IWCONFIG_COMMAND, IWCONFIG_COMMAND, INTERFACE, 'mode', mode )
  262.         iwconfig_args.append( 'mode' )
  263.         iwconfig_args.append( mode )
  264.     # Now the channel
  265.     channel    = profile['channel']
  266.     if channel != '':
  267.         if __debug__:
  268.             print "Setting channel ", channel
  269.         #os.spawnlp( os.P_WAIT, IWCONFIG_COMMAND, IWCONFIG_COMMAND, INTERFACE, 'channel', channel )
  270.         iwconfig_args.append( 'channel' )
  271.         iwconfig_args.append( channel )
  272.     # Some cards require a commit
  273.     if COMMIT_REQUIRED:
  274.         if __debug__:
  275.             print "Setting commit "
  276.         #os.spawnlp( os.P_WAIT, IWCONFIG_COMMAND, IWCONFIG_COMMAND, INTERFACE, 'commit' )
  277.         iwconfig_args.append( 'commit' )
  278.     if __debug__:
  279.         print "iwconfig_args %s " % ( iwconfig_args, )
  280.     iwconfig_command = IWCONFIG_COMMAND + ' ' + ' '.join( iwconfig_args )
  281.     #os.spawnvp( os.P_WAIT, IWCONFIG_COMMAND, iwconfig_args )
  282.     if __debug__:
  283.         print "iwconfig_command ", iwconfig_command
  284.     os.system( iwconfig_command )
  285.     # Now normal network stuff
  286.     # Kill off any existing DHCP clients running
  287.     if os.access( DHCP_PIDFILE, os.R_OK):
  288.         if __debug__:
  289.             print "Killing existing DHCP..."
  290.         try:
  291.             if not DHCP_KILL_COMMAND == '':
  292.                 os.spawnlp( os.P_WAIT, DHCP_KILL_COMMAND, DHCP_KILL_COMMAND )
  293.             os.kill( int(open(DHCP_PIDFILE, mode='r').readline()), signal.SIGTERM )
  294.         except OSError:
  295.             print "Stale pid file.  Removing"
  296.             os.remove( DHCP_PIDFILE )
  297.         if os.path.isfile( DHCP_PIDFILE ):
  298.             print "Stale pid file.  Removing"
  299.             os.remove( DHCP_PIDFILE )
  300.     if os.access( WPA_SUPPLICANT_PIDFILE, os.R_OK):
  301.         if __debug__:
  302.             print "Killing existing WPA_SUPPLICANT..."
  303.         try:
  304.             if not WPA_SUPPLICANT_KILL_COMMAND == '':
  305.                 os.spawnlp( os.P_WAIT, WPA_SUPPLICANT_KILL_COMMAND, WPA_SUPPLICANT_KILL_COMMAND )
  306.             os.kill( int(open(WPA_SUPPLICANT_PIDFILE, mode='r').readline()), signal.SIGTERM )
  307.         except OSError:
  308.                    print "Stale pid file.  Removing"
  309.             os.remove( WPA_SUPPLICANT_PIDFILE )
  310.         if os.path.isfile( WPA_SUPPLICANT_PIDFILE ):
  311.             print "Stale pid file.  Removing"
  312.             os.remove( WPA_SUPPLICANT_PIDFILE )
  313.     use_wpa = profile['use_wpa']
  314.     if use_wpa :
  315.         wpa_options = list()
  316.         wpa_options.append( WPA_SUPPLICANT_COMMAND )
  317.         wpa_args = WPA_SUPPLICANT_ARGS % ( INTERFACE, profile['wpa_driver'] )
  318.         wpa_options.extend( wpa_args.split() )
  319.         wpa_options.append( INTERFACE )
  320.         if __debug__:
  321.             print "WPA args: %s" % ( wpa_options, )
  322.         if status_win:
  323.             status_win.update_message("wpa supplicant")
  324.         wpa_pid = os.spawnvp(os.P_NOWAIT,WPA_SUPPLICANT_COMMAND, wpa_options)
  325.  
  326.     use_dhcp = profile['use_dhcp']
  327.     if use_dhcp :
  328.         dhcp_options = list()
  329.         dhcp_options.append(DHCP_COMMAND)
  330.         dhcp_options.extend(DHCP_ARGS.split())
  331.         dhcp_options.append(INTERFACE)
  332.         if __debug__:
  333.             print "DHCP args: %s" % ( dhcp_options, )
  334.         if status_win:
  335.             status_win.update_message("Acquiring IP Address")
  336.         dhcp_pid = os.spawnvp(os.P_NOWAIT,DHCP_COMMAND, dhcp_options)
  337.         timer = DHCP_TIMEOUT
  338.         tick = 0.25
  339.         while os.waitpid(dhcp_pid,os.WNOHANG) == (0,0):
  340.             if timer < 0:
  341.                 os.kill( dhcp_pid, signal.SIGTERM)
  342.                 break
  343.             if sys.modules.has_key("gtk"):
  344.                 while gtk.events_pending():
  345.                     gtk.main_iteration(False)
  346.             timer -= tick
  347.             time.sleep(tick)
  348.          if not get_current_ip():
  349.              if status_win:
  350.                  status_win.update_message("Could not get IP address!")
  351.                  if sys.modules.has_key("gtk"):
  352.                      while gtk.events_pending():
  353.                          gtk.main_iteration(False)
  354.                  time.sleep(3)
  355.              else:
  356.                  print "Could not get IP address!"
  357.              return
  358.          else:
  359.              if status_win:
  360.                  status_win.update_message("Got IP address. Done")
  361.                  if sys.modules.has_key("gtk"):
  362.                      while gtk.events_pending():
  363.                          gtk.main_iteration(False)
  364.                  time.sleep(2)
  365.     else:
  366.         ip         = profile['ip']
  367.         netmask = profile['netmask']
  368.         gateway = profile['gateway']
  369.         domain    = profile['domain']
  370.         dns1    = profile['dns1']
  371.         dns2     = profile['dns2']
  372.         ifconfig_command= "%s %s down; %s %s %s netmask %s" % \
  373.             ( IFCONFIG_COMMAND, INTERFACE, IFCONFIG_COMMAND, INTERFACE, ip, netmask )
  374.         route_command     = "%s add default gw %s" % ( ROUTE_COMMAND, gateway )
  375.         if domain != '':
  376.             domain         = "domain %s\n" % domain
  377.         if dns1 != '':
  378.             dns1         = "nameserver %s\n" % dns1
  379.         if dns2 != '':
  380.             dns2         = "nameserver %s\n" % dns2
  381.         if ( domain != '' ) or ( dns1 != '' ) or ( dns2 != '' ):
  382.             dns_command    = "echo \"%s%s%s\" > /etc/resolv.conf" % ( domain, dns1, dns2 )
  383.             os.system( dns_command )
  384.         os.system( ifconfig_command )
  385.         os.system( route_command )
  386.         if __debug__:
  387.             print "connect_debug %s %s %s" % (dns_command, ifconfig_command, route_command)
  388.         # Let's run the postscript
  389.         postscript = profile['postscript']
  390.         if postscript.strip() != '':
  391.             # got something to execute
  392.             if __debug__:
  393.                 print "executing postscript:", postscript
  394.             os.system( postscript )
  395.  
  396. def    disconnect_interface():
  397.     msg = "Disconnecting"
  398.     say( msg )
  399.     if __debug__:
  400.         print msg
  401.     # Lets clear out the wireless stuff
  402.     os.spawnlp( os.P_WAIT, IWCONFIG_COMMAND, IWCONFIG_COMMAND, INTERFACE, 'essid', 'off' )
  403.     os.spawnlp( os.P_WAIT, IWCONFIG_COMMAND, IWCONFIG_COMMAND, INTERFACE, 'key', 'off' )
  404.     os.spawnlp( os.P_WAIT, IWCONFIG_COMMAND, IWCONFIG_COMMAND, INTERFACE, 'mode', 'auto' )
  405.     os.spawnlp( os.P_WAIT, IWCONFIG_COMMAND, IWCONFIG_COMMAND, INTERFACE, 'channel', 'auto' )
  406.     # Now take the interface down
  407.     os.spawnlp( os.P_WAIT, IFCONFIG_COMMAND, IFCONFIG_COMMAND, INTERFACE, 'down' )
  408.     if __debug__:
  409.         print "discon_debug"
  410.     # Kill off any existing DHCP clients running
  411.     if os.access( DHCP_PIDFILE, os.R_OK):
  412.         if __debug__:
  413.             print "Killing existing DHCP..."
  414.         try:
  415.             if not DHCP_KILL_COMMAND == '':
  416.                 os.spawnlp( os.P_WAIT, DHCP_KILL_COMMAND, DHCP_KILL_COMMAND )
  417.             os.kill( int(open(DHCP_PIDFILE, mode='r').readline()), signal.SIGTERM )
  418.         except OSError:
  419.             print "Stale pid file.  Removing"
  420.             os.remove( DHCP_PIDFILE )
  421.         if os.path.isfile( DHCP_PIDFILE ):
  422.             print "Stale pid file.  Removing"
  423.             os.remove( DHCP_PIDFILE )
  424.     # Kill off any existing WPA_SUPPLICANT clients running
  425.     if os.access( WPA_SUPPLICANT_PIDFILE, os.R_OK):
  426.         if __debug__:
  427.             print "Killing existing WPA_SUPPLICANT..."
  428.         try:
  429.             if not WPA_SUPPLICANT_KILL_COMMAND == '':
  430.                 os.spawnlp( os.P_WAIT, WPA_SUPPLICANT_KILL_COMMAND, WPA_SUPPLICANT_KILL_COMMAND )
  431.             os.kill( int(open(WPA_SUPPLICANT_PIDFILE, mode='r').readline()), signal.SIGTERM )
  432.         except OSError:
  433.             print "Stale pid file.  Removing"
  434.             os.remove( WPA_SUPPLICANT_PIDFILE )
  435.         if os.path.isfile( WPA_SUPPLICANT_PIDFILE ):
  436.             print "Stale pid file.  Removing"
  437.             os.remove( WPA_SUPPLICANT_PIDFILE )
  438.  
  439. def get_profile_from_conf_file( essid ):
  440.     global config_options
  441.     # We got the essid, get the key
  442.     profile = {}
  443.     if not confFile.has_section( essid ):
  444.         return None
  445.     profile['ssid']        = essid
  446.     profile['key']        = ''
  447.     profile['mode']        = ''
  448.     profile['security']    = ''
  449.     profile['prescript']= ''
  450.     profile['postscript']= ''
  451.     profile['channel']    = ''
  452.     profile['signal']    = '0'
  453.     profile['protocol']    = 'b'
  454.     if confFile.has_option( essid, "key" ):
  455.         profile['key']    = confFile.get( essid, "key" )
  456.     if confFile.has_option( essid, "mode" ):
  457.         profile['mode']    = confFile.get( essid, "mode" )
  458.     if confFile.has_option( essid, "security" ):
  459.         profile['security']    = confFile.get( essid, "security" )
  460.     if confFile.has_option( essid, "prescript" ):
  461.         profile['prescript']= confFile.get( essid, "prescript" )
  462.     if confFile.has_option( essid, "postscript" ):
  463.         profile['postscript']= confFile.get( essid, "postscript" )
  464.     if confFile.has_option( essid, "channel" ):
  465.         profile['channel']    = confFile.get( essid, "channel" )
  466.     # Now normal network
  467.     profile['use_wpa']    = False
  468.     if confFile.has_option( essid, "use_wpa" ):
  469.         profile['use_wpa'] = confFile.getboolean( essid, "use_wpa" )
  470.     profile['wpa_driver']         = ''
  471.     if confFile.has_option( essid, "wpa_driver" ):
  472.         profile['wpa_driver']    = confFile.get( essid, "wpa_driver" )
  473.     profile['use_dhcp']    = False
  474.     if confFile.has_option( essid, "use_dhcp" ):
  475.         profile['use_dhcp'] = confFile.getboolean( essid, "use_dhcp" )
  476.     profile['ip']         = ''
  477.     if confFile.has_option( essid, "ip" ):
  478.         profile['ip']    = confFile.get( essid, "ip" )
  479.     profile['netmask']    = ''
  480.     if confFile.has_option( essid, "netmask" ):
  481.         profile['netmask'] = confFile.get( essid, "netmask" )
  482.     profile['gateway']    = ''
  483.     if confFile.has_option( essid, "gateway" ):
  484.         profile['gateway'] = confFile.get( essid, "gateway" )
  485.     profile['domain']    = ''
  486.     if confFile.has_option( essid, "domain" ):
  487.         profile['domain'] = confFile.get( essid, "domain" )
  488.     profile['dns1']        = ''
  489.     if confFile.has_option( essid, "dns1" ):
  490.         profile['dns1'] = confFile.get( essid, "dns1" )
  491.     profile['dns2']        = ''
  492.     if confFile.has_option( essid, "dns2" ):
  493.         profile['dns2'] = confFile.get( essid, "dns2" )
  494.     return profile
  495.  
  496. def set_profile_to_conf_file( profile ):
  497.     if not confFile.has_section( profile['ssid'] ):
  498.         confFile.add_section( profile['ssid'] )
  499.     confFile.set( profile['ssid'], 'key', profile['key'] )
  500.     confFile.set( profile['ssid'], 'security', profile['security'] )
  501.     confFile.set( profile['ssid'], 'prescript', profile['prescript'] )
  502.     confFile.set( profile['ssid'], 'postscript', profile['postscript'] )
  503.     confFile.set( profile['ssid'], 'mode', profile['mode'] )
  504.     confFile.set( profile['ssid'], 'channel', profile['channel'] )
  505.     # wpa
  506.     if profile['use_wpa']:
  507.         confFile.set( profile['ssid'], 'use_wpa', 'yes' )
  508.         confFile.set( profile['ssid'], 'wpa_driver', profile['wpa_driver'] )
  509.     else:
  510.         confFile.set( profile['ssid'], 'use_wpa', 'no' )
  511.     # dhcp
  512.     if profile['use_dhcp']:
  513.         confFile.set( profile['ssid'], 'use_dhcp', 'yes' )
  514.         try: confFile.remove_option( profile['ssid'], 'ip' )
  515.         except: pass
  516.         try: confFile.remove_option( profile['ssid'], 'netmask' )
  517.         except: pass
  518.         try: confFile.remove_option( profile['ssid'], 'gateway' )
  519.         except: pass
  520.         try: confFile.remove_option( profile['ssid'], 'domain' )
  521.         except: pass
  522.         try: confFile.remove_option( profile['ssid'], 'dns1' )
  523.         except: pass
  524.         try: confFile.remove_option( profile['ssid'], 'dns2' )
  525.         except: pass
  526.     else:
  527.         confFile.set( profile['ssid'], 'use_dhcp', 'no' )
  528.         confFile.set( profile['ssid'], 'ip', profile['ip'] )
  529.         confFile.set( profile['ssid'], 'netmask', profile['netmask'] )
  530.         confFile.set( profile['ssid'], 'gateway', profile['gateway'] )
  531.         confFile.set( profile['ssid'], 'domain', profile['domain'] )
  532.         confFile.set( profile['ssid'], 'dns1', profile['dns1'] )
  533.         confFile.set( profile['ssid'], 'dns2', profile['dns2'] )
  534.     confFile.write( open( CONF_FILE, "w" ) )
  535.  
  536. ##################
  537. # The main window
  538. class radar_window:
  539.     def __init__( self ):
  540.         # create the main window and connect the normal events
  541.         global    signal_xpm_none
  542.         global    signal_xpm_low
  543.         global    signal_xpm_barely
  544.         global    signal_xpm_ok
  545.         global    signal_xpm_best
  546.         global    known_profile_icon
  547.         global    unknown_profile_icon
  548.         global    wifi_radar_icon
  549.         self.signal_none_pb    = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_none )
  550.         self.known_profile_icon        = gtk.gdk.pixbuf_new_from_inline( len( known_profile_icon[0] ), known_profile_icon[0], False )
  551.         self.unknown_profile_icon    = gtk.gdk.pixbuf_new_from_inline( len( unknown_profile_icon[0] ), unknown_profile_icon[0], False )
  552.         self.signal_low_pb    = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_low )
  553.         self.signal_barely_pb= gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_barely )
  554.         self.signal_ok_pb    = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_ok )
  555.         self.signal_best_pb    = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_best )
  556.         self.window = gtk.Dialog('WiFi Radar', None, gtk.DIALOG_MODAL )
  557.         icon = gtk.gdk.pixbuf_new_from_inline( len( wifi_radar_icon[0] ), wifi_radar_icon[0], False )
  558.         self.window.set_icon( icon )
  559.         self.window.set_border_width( 10 )
  560.         self.window.set_size_request( 450, 300 )
  561.         self.window.set_title( "WiFi Radar" )
  562.         self.window.connect( 'delete_event', self.delete_event )
  563.         self.window.connect( 'destroy', self.destroy, )
  564.         # let's create all our widgets
  565.         self.instructions = gtk.Label("My preferred WiFi networks")
  566.         self.instructions.show()
  567.         self.current_network = gtk.Label()
  568.         self.current_network.show()
  569.         self.close_button = gtk.Button( "Close", gtk.STOCK_CLOSE )
  570.         self.close_button.show()
  571.         self.close_button.connect( 'clicked', self.delete_event, None  )
  572.         #                            apname known_icon      known available wep_icon signal_level    mode protocol
  573.         self.pstore = gtk.ListStore( str,   gtk.gdk.Pixbuf, int,  int,      str,     gtk.gdk.Pixbuf, str, str )
  574.         self.rebuild_plist_items()
  575.         self.plist = gtk.TreeView( self.pstore )
  576.         self.pcol    = gtk.TreeViewColumn( "SSID" )
  577.         # The ssid column
  578.         self.plist.append_column( self.pcol )
  579.         self.pix_cell     = gtk.CellRendererPixbuf()
  580.         self.wep_cell     = gtk.CellRendererPixbuf()
  581.         self.ssid_cell     = gtk.CellRendererText()
  582.         self.pcol.pack_start( self.pix_cell, False )
  583.         self.pcol.pack_start( self.wep_cell, False )
  584.         self.pcol.pack_start( self.ssid_cell, True )
  585.         self.pcol.add_attribute( self.wep_cell, 'stock-id', 4 )
  586.         self.pcol.add_attribute( self.pix_cell, 'pixbuf', 1 )
  587.         self.pcol.add_attribute( self.ssid_cell, 'text', 0 )
  588.         self.sig_cell     = gtk.CellRendererPixbuf()
  589.         self.scol    = gtk.TreeViewColumn( "Signal" )
  590.         self.scol.pack_start( self.sig_cell, True )
  591.         self.scol.add_attribute( self.sig_cell, 'pixbuf', 5 )
  592.         self.plist.append_column( self.scol )
  593.         # The mode column
  594.         self.mode_cell     = gtk.CellRendererText()
  595.         self.mcol    = gtk.TreeViewColumn( "Mode" )
  596.         self.mcol.pack_start( self.mode_cell, True )
  597.         self.mcol.add_attribute( self.mode_cell, 'text', 6 )
  598.         self.plist.append_column( self.mcol )
  599.         # The protocol column
  600.         self.prot_cell     = gtk.CellRendererText()
  601.         self.protcol    = gtk.TreeViewColumn( "802.11" )
  602.         self.protcol.pack_start( self.prot_cell, True )
  603.         self.protcol.add_attribute( self.prot_cell, 'text', 7 )
  604.         self.plist.append_column( self.protcol )
  605.         # DnD Ordering
  606.         self.plist.set_reorderable( True )
  607.         self.pstore.connect( 'row-changed', self.save_auto_profile_order )
  608.         # the list scroll bar
  609.         sb = gtk.VScrollbar( self.plist.get_vadjustment() )
  610.         sb.show()
  611.         self.plist.show()
  612.         #
  613.         self.new_button = gtk.Button( "New" )
  614.         self.new_button.connect( 'clicked', self.create_new_profile, None  )
  615.         self.new_button.show()
  616.         #
  617.         self.edit_button = gtk.Button( "Edit" )
  618.         self.edit_button.connect( 'clicked', self.edit_profile, None  )
  619.         self.edit_button.show()
  620.         #
  621.         self.delete_button = gtk.Button( "Delete" )
  622.         self.delete_button.connect( 'clicked', self.delete_profile, None  )
  623.         self.delete_button.show()
  624.         #
  625.         self.connect_button = gtk.Button( "Connect" )
  626.         self.connect_button.connect( 'clicked', self.connect_profile, None  )
  627.         self.connect_button.show()
  628.         #
  629.         self.disconnect_button = gtk.Button( "Disconnect" )
  630.         self.disconnect_button.connect( 'clicked', self.disconnect_profile, None  )
  631.         self.disconnect_button.show()
  632.         # lets add our widgets
  633.         rows        = gtk.VBox( False, 3 )
  634.         listcols    = gtk.HBox( False, 0 )
  635.         prows        = gtk.VBox( False, 0 )
  636.         # lets start packing
  637.         # the rows level
  638.         rows.pack_start( self.instructions, False, True, 0 )
  639.         rows.pack_start( listcols, True, True, 0 )
  640.         rows.pack_start( self.current_network, False, True, 0 )
  641.         # the list columns
  642.         listcols.pack_start( self.plist, True, True, 0 )
  643.         listcols.pack_start( sb, False, False, 0 )
  644.         listcols.pack_start( prows, False, False, 5 )
  645.         # the list buttons
  646.         prows.pack_start( self.new_button, False, False, 2 )
  647.         prows.pack_start( self.edit_button, False, False, 2 )
  648.         prows.pack_start( self.delete_button, False, False, 2 )
  649.         prows.pack_start( gtk.HSeparator(), False, False, 4 )
  650.         prows.pack_start( self.connect_button, False, False, 2 )
  651.         prows.pack_start( self.disconnect_button, False, False, 2 )
  652.         #self.window.action_area.set_homogeneous( True )
  653.         #self.window.action_area.pack_start( self.current_network )
  654.         self.window.action_area.pack_start( self.close_button )
  655.         rows.show()
  656.         listcols.show()
  657.         prows.show()
  658.         self.window.vbox.add( rows )
  659.         self.window.vbox.set_spacing( 3 )
  660.         self.window.show_all()
  661.  
  662.     def main( self ):
  663.         gtk.main()
  664.  
  665.     def destroy( self, widget = None):
  666.         global lock
  667.         if not lock.locked():
  668.             lock.acquire()
  669.         gtk.main_quit()
  670.         try: lock.release()
  671.         except: pass
  672.  
  673.     def delete_event( self, widget, event, data=None ):
  674.         # Save the preferred networks order
  675.         global exit_flag
  676.         exit_flag = True
  677.         self.save_auto_profile_order()
  678.         self.destroy()
  679.         return False
  680.  
  681.     def rebuild_plist_items( self ):
  682.         # Add our known profiles in order
  683.         global lock
  684.         try:     lock.acquire()
  685.         except:    pass
  686.         for ssid in auto_profile_order:
  687.             ssid = ssid.strip()
  688.             if access_points.has_key( ssid ) and access_points[ ssid ]['known']:
  689.                 wep = None
  690.                 if access_points[ ssid ]['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION
  691.                 # 1 here means that we know this ssid ---------------v
  692.                 self.pstore.append( [ ssid, self.known_profile_icon, 1, 0, wep, self.signal_none_pb, access_points[ ssid ]['mode'], access_points[ ssid ]['protocol'] ] )
  693.         # Now add any known profiles not in the profile order
  694.         for ap in access_points:
  695.             if ap in auto_profile_order: continue
  696.             wep = None
  697.             if access_points[ ap ]['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION
  698.             # 1 here means that we know this ssid ---------------v
  699.             self.pstore.append( [ ap, self.unknown_profile_icon, 0, 0, wep, self.signal_none_pb, access_points[ ap ]['mode'], access_points[ ap ]['protocol'] ] )
  700.         try:    lock.release()
  701.         except: pass
  702.  
  703.     def update_plist_items( self ):
  704.         """Updates the profiles list"""
  705.         global lock
  706.         global current_ip
  707.         global current_ssid
  708.         #if __debug__:
  709.         #    print "updating profile list"
  710.         gtk.threads_enter()
  711.         if not lock.locked():
  712.             lock.acquire()
  713.         # update the current ip and ssid
  714.         self.current_network.set_text( "Connected to %s ip(%s)" % ( current_ssid, current_ip ) )
  715.         for ap in access_points:
  716.             wep = None
  717.             if access_points[ ap ]['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION
  718.             prow = self.get_row_by_ssid( ap )
  719.             if prow:
  720.                 #if __debug__:
  721.                 #    print "Setting prow", ap, access_points[ ap ]
  722.                 prow[4] = wep
  723.                 prow[5] = self.pixbuf_from_signal( access_points[ ap ][ 'signal' ] )
  724.                 prow[6] = access_points[ ap ][ 'mode' ]
  725.                 prow[7] = access_points[ ap ][ 'protocol' ]
  726.                 #for val in prow:
  727.                 #    print val
  728.             else:
  729.                 #if __debug__:
  730.                 #    print "New profile", ap, access_points[ ap ]
  731.                 # 1 here means that we know this ssid ---------------v
  732.                 self.pstore.append( [ ap, self.unknown_profile_icon, 0, 0, wep,
  733.                     self.pixbuf_from_signal( access_points[ ap ]['signal'] ),
  734.                     access_points[ ap ]['mode'],
  735.                     access_points[ ap ]['protocol'] ] )
  736.             # give the list a chance to update
  737.             #while gtk.events_pending():
  738.             #    gtk.main_iteration()
  739.         try: lock.release()
  740.         except: pass
  741.         gtk.threads_leave()
  742.         return True
  743.  
  744.     def pixbuf_from_signal( self, signal ):
  745.         signal = int( signal )
  746.         #print signal
  747.         if signal >= 80 or signal == 0:
  748.             return self.signal_none_pb
  749.         elif signal >= 78:
  750.             return self.signal_low_pb
  751.         elif signal >= 75:
  752.             return self.signal_barely_pb
  753.         elif signal >= 60:
  754.             return self.signal_ok_pb
  755.         elif signal < 60:
  756.             return self.signal_best_pb
  757.         else:
  758.             return None
  759.  
  760.     def get_row_by_ssid( self, ssid ):
  761.         for row in self.pstore:
  762.             if row[0] == ssid:
  763.                 #print row
  764.                 return row
  765.         return None
  766.  
  767.     def create_new_profile( self, widget, data=None ):
  768.         global lock
  769.         p = profile_dialog( self )
  770.         while True:
  771.             ok = p.run()
  772.             if ok:
  773.                 profile = p.get_profile()
  774.                 # Check that the ssid does not exist already
  775.                 if profile['ssid'] in access_points:
  776.                     dlg = gtk.MessageDialog(
  777.                         self.window,
  778.                         gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
  779.                         gtk.MESSAGE_ERROR,
  780.                         gtk.BUTTONS_OK,
  781.                         "A profile for %s already exists" % profile['ssid'] )
  782.                     dlg.run()
  783.                     dlg.destroy()
  784.                     del dlg
  785.                     # try again
  786.                     continue
  787.                 set_profile_to_conf_file( profile )
  788.                 # Add lets add it up
  789.                 ap = {}
  790.                 ap['known']        = True
  791.                 ap['available']    = False
  792.                 ap['encrypted'] = False
  793.                 ap['mode']        = ''
  794.                 ap['security']    = ''
  795.                 ap['prescript']    = ''
  796.                 ap['postscript']= ''
  797.                 ap['channel']    = ''
  798.                 ap['protocol']    = 'b'
  799.                 ap['signal']    = '0'
  800.                 if confFile.has_option( profile['ssid'], 'key'):
  801.                     if len( confFile.get( profile['ssid'], 'key' ) ) > 0:
  802.                         ap['encrypted'] = True
  803.                 lock.acquire()
  804.                 access_points[ profile['ssid'] ] = ap
  805.                 # if it is not in the auto_profile_order add it
  806.                 if not profile['ssid'] in auto_profile_order:
  807.                     auto_profile_order.append( profile['ssid'] )
  808.                 lock.release()
  809.                 # add to the store
  810.                 wep = None
  811.                 if ap['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION
  812.                 self.pstore.append( [ profile['ssid'], self.known_profile_icon, 1, 0, wep, self.pixbuf_from_signal( ap['signal'] ), ap['mode'], ap['protocol'] ] )
  813.             break
  814.         p.destroy()
  815.  
  816.     def edit_profile( self, widget, data=None ):
  817.         ( store, selected_iter ) = self.plist.get_selection().get_selected()
  818.         if not selected_iter: return
  819.         ssid    = store.get_value( selected_iter, 0 )
  820.         known    = store.get_value( selected_iter, 2 )
  821.         if not known: return
  822.         profile = get_profile_from_conf_file( ssid )
  823.         p = profile_dialog( self )
  824.         p.set_profile( profile, True )
  825.         ok = p.run()
  826.         if ok:
  827.             profile = p.get_profile()
  828.             if __debug__:
  829.                 print "Got edited profile ", profile
  830.             set_profile_to_conf_file( profile )
  831.         p.destroy()
  832.  
  833.     def delete_profile( self, widget, data=None ):
  834.         ( store, selected_iter ) = self.plist.get_selection().get_selected()
  835.         if not selected_iter: return
  836.         ssid    = store.get_value( selected_iter, 0 )
  837.         known    = store.get_value( selected_iter, 2 )
  838.         if not known: return
  839.         dlg = gtk.MessageDialog(
  840.                     self.window,
  841.                     gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
  842.                     gtk.MESSAGE_QUESTION,
  843.                     gtk.BUTTONS_YES_NO,
  844.                 "Are you sure you want to delete the %s profile?" % ssid )
  845.         res = dlg.run()
  846.         dlg.destroy()
  847.         del dlg
  848.         if res == gtk.RESPONSE_NO: return
  849.         # Remove it
  850.         confFile.remove_section( ssid )
  851.         if ssid in auto_profile_order: auto_profile_order.remove( ssid )
  852.         if access_points.has_key( ssid ): access_points.pop( ssid )
  853.         self.pstore.remove( selected_iter )
  854.         # Let's save our current state
  855.         self.save_auto_profile_order()
  856.  
  857.     def connect_profile( self, widget, data=None ):
  858.         ( store, selected_iter ) = self.plist.get_selection().get_selected()
  859.         if not selected_iter: return
  860.         ssid    = store.get_value( selected_iter, 0 )
  861.         known    = store.get_value( selected_iter, 2 )
  862.         if not known:
  863.             dlg = gtk.MessageDialog(
  864.                     self.window,
  865.                     gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
  866.                     gtk.MESSAGE_QUESTION,
  867.                     gtk.BUTTONS_YES_NO,
  868.                 "This network does not have a profile configured.\n\nWould you like to create one now?" )
  869.             res = dlg.run()
  870.             dlg.destroy()
  871.             del dlg
  872.             if res == gtk.RESPONSE_NO: return
  873.             p = profile_dialog( self )
  874.             # get a blank profile from the dialog
  875.             profile = p.get_profile()
  876.             profile['ssid'] = ssid
  877.             p.set_profile( profile, True )
  878.             ok = p.run()
  879.             if ok:
  880.                 profile = p.get_profile()
  881.                 set_profile_to_conf_file( profile )
  882.                 # change the icon
  883.                 self.pstore.set_value( selected_iter, 1, self.known_profile_icon )
  884.                 # make it known
  885.                 self.pstore.set_value( selected_iter, 2, 1 )
  886.                 # if it is not in the auto_profile_order add it
  887.                 if not profile['ssid'] in auto_profile_order:
  888.                     auto_profile_order.append( profile['ssid'] )
  889.                 self.save_auto_profile_order()
  890.                 p.destroy()
  891.                 connect_status_window = status_window()
  892.                 connect_status_window.run()
  893.                 connect_to_network( ssid, connect_status_window )
  894.                 connect_status_window.destroy()
  895.             else:
  896.                 p.destroy()
  897.         else:
  898.             connect_status_window = status_window()
  899.             connect_status_window.run()
  900.             connect_to_network( ssid, connect_status_window )
  901.             connect_status_window.destroy()
  902.  
  903.     def disconnect_profile( self, widget, data=None ):
  904.         disconnect_interface()
  905.  
  906.     def get_ssid_iter( self, ssid ):
  907.         piter = self.pstore.get_iter_first()
  908.         while piter:
  909.             # only if it's known
  910.             if self.pstore.get_value( piter, 0 ) == ssid: break
  911.         return piter
  912.  
  913.     def save_auto_profile_order( self, widget = None, data = None, data2 = None ):
  914.         # recreate the auto_profile_order
  915.         auto_profile_order = []
  916.         piter = self.pstore.get_iter_first()
  917.         while piter:
  918.             # only if it's known
  919.             if self.pstore.get_value( piter, 2 ) == 1:
  920.                 auto_profile_order.append( self.pstore.get_value( piter, 0 ) )
  921.             piter = self.pstore.iter_next( piter )
  922.         # save it
  923.         apo = ','.join( auto_profile_order )
  924.         confFile.set( 'DEFAULT', 'auto_profile_order', apo )
  925.         confFile.write( open( CONF_FILE, 'w' ) )
  926.  
  927. ###################################
  928. class profile_dialog:
  929.     def __init__( self, parent ):
  930.         global wifi_radar_icon
  931.         self.parent = parent
  932.         self.dialog = gtk.Dialog('WiFi Profile', self.parent.window,
  933.                                 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
  934.                                 ( gtk.STOCK_CANCEL, False, gtk.STOCK_SAVE, True ) )
  935.         icon = gtk.gdk.pixbuf_new_from_inline( len( wifi_radar_icon[0] ), wifi_radar_icon[0], False )
  936.         self.dialog.set_icon( icon )
  937.         self.dialog.set_resizable( False )
  938.         self.dialog.set_transient_for( self.parent.window )
  939.         #self.dialog.set_size_request( 400, 400 )
  940.         ssid_table = gtk.Table( 1, 2, False )
  941.         ssid_table.set_row_spacings( 3 )
  942.         ssid_table.set_col_spacings( 3 )
  943.         #################
  944.         # The ssid labels
  945.         l = gtk.Label( 'Network Name' )
  946.         ssid_table.attach( l, 0, 1, 0, 1 )
  947.         # The ssid textboxes
  948.         self.ssid = gtk.Entry( 32 )
  949.         self.ssid.set_text('ssid')
  950.         ssid_table.attach( self.ssid, 1, 2, 0, 1 )
  951.         #self.key = gtk.Entry( 32 )
  952.         #ssid_table.attach( self.key, 1, 2, 1, 2 )
  953.         # Add the ssid table to the dialog
  954.         self.dialog.vbox.pack_start( ssid_table, True, True, 5 )
  955.  
  956.  
  957.         # create the wifi expander
  958.         self.wifi_expander = gtk.Expander( WIFI_SET_LABEL )
  959.         wifi_table = gtk.Table( 4, 2, False )
  960.         wifi_table.set_row_spacings( 3 )
  961.         wifi_table.set_col_spacings( 3 )
  962.         # The Wifi labels
  963.         l = gtk.Label( 'Mode' )
  964.         wifi_table.attach( l, 0, 1, 0, 1 )
  965.         l = gtk.Label( 'Channel' )
  966.         wifi_table.attach( l, 0, 1, 1, 2 )
  967.         l = gtk.Label( 'Key' )
  968.         wifi_table.attach( l, 0, 1, 2, 3 )
  969.         l = gtk.Label( 'Security' )
  970.         wifi_table.attach( l, 0, 1, 3, 4 )
  971.         # The Wifi text boxes
  972.         self.mode = gtk.combo_box_new_text()
  973.         for mode in WIFI_MODES:
  974.             self.mode.append_text( mode )
  975.         self.mode.set_active( 0 )
  976.         wifi_table.attach( self.mode, 1, 2, 0, 1 )
  977.         self.channel = gtk.combo_box_new_text()
  978.         for channel in WIFI_CHANNELS:
  979.             self.channel.append_text( channel )
  980.         self.channel.set_active( 0 )
  981.         wifi_table.attach( self.channel, 1, 2, 1, 2 )
  982.         self.key = gtk.Entry( 32 )
  983.         #self.key.set_text('0.0.0.0')
  984.         wifi_table.attach( self.key, 1, 2, 2, 3 )
  985.         self.security = gtk.combo_box_new_text()
  986.         for security in WIFI_SECURITY:
  987.             self.security.append_text( security )
  988.         self.security.set_active( 0 )
  989.         wifi_table.attach( self.security, 1, 2, 3, 4 )
  990.         # Add the wifi table to the expander
  991.         self.wifi_expander.add( wifi_table )
  992.         # Add the expander to the dialog
  993.         self.dialog.vbox.pack_start( self.wifi_expander, False, False, 5 )
  994.  
  995.         # create the wpa expander
  996.         self.wpa_expander = gtk.Expander( NO_WPA_LABEL )
  997.         self.wpa_expander.connect( 'notify::expanded', self.toggle_use_wpa )
  998.         wpa_table = gtk.Table( 1, 2, False )
  999.         wpa_table.set_row_spacings( 3 )
  1000.         wpa_table.set_col_spacings( 3 )
  1001.         # The labels
  1002.         l = gtk.Label( 'Driver' )
  1003.         wpa_table.attach( l, 0, 1, 0, 1 )
  1004.         # The text boxes
  1005.         self.wpa_driver = gtk.Entry()
  1006.         wpa_table.attach( self.wpa_driver, 1, 2, 0, 1 )
  1007.         # Add the wpa table to the expander
  1008.         self.wpa_expander.add( wpa_table )
  1009.         # Add the expander to the dialog
  1010.         self.dialog.vbox.pack_start( self.wpa_expander, False, False, 5 )
  1011.  
  1012.         # create the dhcp expander
  1013.         self.dhcp_expander = gtk.Expander( USE_DHCP_LABEL )
  1014.         self.dhcp_expander.connect( 'notify::expanded', self.toggle_use_dhcp )
  1015.         ip_table = gtk.Table( 6, 2, False )
  1016.         ip_table.set_row_spacings( 3 )
  1017.         ip_table.set_col_spacings( 3 )
  1018.         # The IP labels
  1019.         l = gtk.Label( 'IP' )
  1020.         ip_table.attach( l, 0, 1, 0, 1 )
  1021.         l = gtk.Label( 'Netmask' )
  1022.         ip_table.attach( l, 0, 1, 1, 2 )
  1023.         l = gtk.Label( 'Gateway' )
  1024.         ip_table.attach( l, 0, 1, 2, 3 )
  1025.         l = gtk.Label( 'Domain' )
  1026.         ip_table.attach( l, 0, 1, 3, 4 )
  1027.         l = gtk.Label( 'DNS' )
  1028.         ip_table.attach( l, 0, 1, 4, 5 )
  1029.         l = gtk.Label( 'DNS' )
  1030.         ip_table.attach( l, 0, 1, 5, 6 )
  1031.         # The IP text boxes
  1032.         self.ip = gtk.Entry( 15 )
  1033.         self.ip.set_text('0.0.0.0')
  1034.         ip_table.attach( self.ip, 1, 2, 0, 1 )
  1035.         self.netmask = gtk.Entry( 15 )
  1036.         self.netmask.set_text('255.255.255.0')
  1037.         ip_table.attach( self.netmask, 1, 2, 1, 2 )
  1038.         self.gw = gtk.Entry( 15 )
  1039.         self.gw.set_text('0.0.0.0')
  1040.         ip_table.attach( self.gw, 1, 2, 2, 3 )
  1041.         self.domain = gtk.Entry( 32 )
  1042.         self.domain.set_text('domain.com')
  1043.         ip_table.attach( self.domain, 1, 2, 3, 4 )
  1044.         self.dns1 = gtk.Entry( 15 )
  1045.         self.dns1.set_text('0.0.0.0')
  1046.         ip_table.attach( self.dns1, 1, 2, 4, 5 )
  1047.         self.dns2 = gtk.Entry( 15 )
  1048.         self.dns2.set_text('0.0.0.0')
  1049.         ip_table.attach( self.dns2, 1, 2, 5, 6 )
  1050.         # Add the ip table to the expander
  1051.         self.dhcp_expander.add( ip_table )
  1052.         # Add the expander to the dialog
  1053.         self.dialog.vbox.pack_start( self.dhcp_expander, False, False, 5 )
  1054.  
  1055.         # create the postpre expander
  1056.         self.postpre_expander = gtk.Expander( POSTPRE_LABEL )
  1057.         pp_table = gtk.Table( 2, 2, False )
  1058.         pp_table.set_row_spacings( 3 )
  1059.         pp_table.set_col_spacings( 3 )
  1060.         # The labels
  1061.         l = gtk.Label( 'Before' )
  1062.         pp_table.attach( l, 0, 1, 0, 1 )
  1063.         l = gtk.Label( 'After' )
  1064.         pp_table.attach( l, 0, 1, 1, 2 )
  1065.         # The text boxes
  1066.         self.prescript = gtk.Entry()
  1067.         pp_table.attach( self.prescript, 1, 2, 0, 1 )
  1068.         self.postscript = gtk.Entry()
  1069.         pp_table.attach( self.postscript, 1, 2, 1, 2 )
  1070.         # Add the pp table to the expander
  1071.         self.postpre_expander.add( pp_table )
  1072.         # Add the expander to the dialog
  1073.         self.dialog.vbox.pack_start( self.postpre_expander, False, False, 5 )
  1074.  
  1075.     def run( self ):
  1076.         self.dialog.show_all()
  1077.         return self.dialog.run()
  1078.  
  1079.     def destroy( self ):
  1080.         self.dialog.destroy()
  1081.         del self.dialog
  1082.  
  1083.     def toggle_use_dhcp( self, widget, data = None ):
  1084.         expanded = self.dhcp_expander.get_expanded()
  1085.         if expanded:
  1086.             self.dhcp_expander.set_label( USE_IP_LABEL )
  1087.         else:
  1088.             self.dhcp_expander.set_label( USE_DHCP_LABEL )
  1089.  
  1090.     def toggle_use_wpa( self, widget, data = None ):
  1091.         expanded = self.wpa_expander.get_expanded()
  1092.         if expanded:
  1093.             self.wpa_expander.set_label( USE_WPA_LABEL )
  1094.         else:
  1095.             self.wpa_expander.set_label( NO_WPA_LABEL )
  1096.  
  1097.     def get_profile( self ):
  1098.         profile                    = {}
  1099.         profile['ssid']            = self.ssid.get_text().strip()
  1100.         profile['key']            = self.key.get_text().strip()
  1101.         profile['mode']            = self.get_array_item( self.mode.get_active(), WIFI_MODES )
  1102.         profile['security']        = self.get_array_item( self.security.get_active(), WIFI_SECURITY )
  1103.         profile['channel']        = self.get_array_item( self.channel.get_active(), WIFI_CHANNELS )
  1104.         profile['protocol']        = 'b'
  1105.         profile['signal']        = '0'
  1106.         profile['prescript']    = self.prescript.get_text().strip()
  1107.         profile['postscript']    = self.postscript.get_text().strip()
  1108.         # wpa
  1109.         use_wpa                 = ( self.wpa_expander.get_expanded() == False )
  1110.         if use_wpa:
  1111.             profile['use_wpa'] = False
  1112.         else:
  1113.             profile['use_wpa'] = True
  1114.             profile['wpa_driver']= self.wpa_driver.get_text().strip()
  1115.         # dhcp
  1116.         use_dhcp                 = ( self.dhcp_expander.get_expanded() == False )
  1117.         if use_dhcp:
  1118.             profile['use_dhcp'] = True
  1119.         else:
  1120.             profile['use_dhcp'] = False
  1121.             profile['ip']        = self.ip.get_text().strip()
  1122.             profile['netmask']    = self.netmask.get_text().strip()
  1123.             profile['gateway']    = self.gw.get_text().strip()
  1124.             profile['domain']    = self.domain.get_text().strip()
  1125.             profile['dns1']        = self.dns1.get_text().strip()
  1126.             profile['dns2']        = self.dns2.get_text().strip()
  1127.         return profile
  1128.  
  1129.     def set_profile( self, profile, known ):
  1130.         if __debug__:
  1131.             print profile
  1132.         self.ssid.set_text( profile['ssid'] )
  1133.         if known:
  1134.             self.ssid.set_editable( False )
  1135.             self.dialog.set_title( "WiFi Profile for %s" % profile['ssid'] )
  1136.         self.key.set_text( profile['key'] )
  1137.         self.mode.set_active( self.get_array_index( profile['mode'], WIFI_MODES ) )
  1138.         self.channel.set_active( self.get_array_index( profile['channel'], WIFI_CHANNELS ) )
  1139.         self.security.set_active( self.get_array_index( profile['security'], WIFI_SECURITY ) )
  1140.         self.prescript.set_text( profile['prescript'] )
  1141.         self.postscript.set_text( profile['postscript'] )
  1142.         # wpa
  1143.         if profile['use_wpa'] == True:
  1144.             self.wpa_expander.set_expanded( True )
  1145.             self.wpa_driver.set_text( profile['wpa_driver'] )
  1146.         else:
  1147.             self.wpa_expander.set_expanded( False )
  1148.         # dhcp
  1149.         if profile['use_dhcp'] == True:
  1150.             self.dhcp_expander.set_expanded( False)
  1151.         else:
  1152.             self.dhcp_expander.set_expanded( True )
  1153.             self.ip.set_text( profile['ip'] )
  1154.             self.netmask.set_text( profile['netmask']    )
  1155.             self.gw.set_text( profile['gateway'] )
  1156.             self.domain.set_text( profile['domain'] )
  1157.             self.dns1.set_text( profile['dns1'] )
  1158.             self.dns2.set_text( profile['dns2'] )
  1159.  
  1160.     def get_array_index( self, item, array ):
  1161.         try:
  1162.             return array.index( item.strip() )
  1163.         except:
  1164.             pass
  1165.         return 0
  1166.  
  1167.     def get_array_item( self, index, array ):
  1168.         try:
  1169.             return array[ index ]
  1170.         except:
  1171.             pass
  1172.         return ''
  1173.  
  1174. ### status_window
  1175. ###
  1176. ### A simple class for putting up a "Please wait" dialog so the user
  1177. ### doesn't think we've forgotten about them.
  1178. class status_window:
  1179.     def __init__( self ):
  1180.         global wifi_radar_icon
  1181.         self.dialog = gtk.Dialog(title="Working", flags=gtk.DIALOG_MODAL)
  1182.         icon = gtk.gdk.pixbuf_new_from_inline( len( wifi_radar_icon[0] ), wifi_radar_icon[0], False )
  1183.         self.dialog.set_icon( icon )
  1184.         self.lbl = gtk.Label("Please wait...")
  1185.         self.bar = gtk.ProgressBar()
  1186.         self.dialog.vbox.pack_start(self.lbl)
  1187.         self.dialog.vbox.pack_start(self.bar)
  1188.         self.dialog.show_all()
  1189.         self.dialog.connect("delete_event",self.inhibit_close)
  1190.  
  1191.     def update_message( self, message ):
  1192.         self.lbl.set_text(message)
  1193.  
  1194.     def inhibit_close( self, widget, signal ):
  1195.         return True
  1196.  
  1197.     def update_window( self ):
  1198.         # Do stuff
  1199.         self.bar.pulse()
  1200.         return True
  1201.  
  1202.     def run( self ):
  1203.         self.dialog.show_all()
  1204.         self.timer = gobject.timeout_add(250,self.update_window)
  1205.         return
  1206.  
  1207.     def destroy( self ):
  1208.         gobject.source_remove(self.timer)
  1209.         self.dialog.destroy()
  1210.         del self.dialog
  1211.  
  1212.  
  1213. ####################################################################################################
  1214. # Speaking up
  1215. def    say( words ):
  1216.     if not SPEAK_UP: return
  1217.     words = words.replace( "\"", "\\\"" )
  1218.     os.system( "%s \"%s\"" % ( SAY_COMMAND, words ) )
  1219.     #os.spawnlp( os.P_WAIT, SAY_COMMAND, SAY_COMMAND, words )
  1220.  
  1221. # Configure
  1222. def configure():
  1223.     global main_radar_window
  1224.     global scanner
  1225.     global lock
  1226.     main_radar_window = radar_window()
  1227.     lock = thread.allocate_lock()
  1228.     thread.start_new( scanning_thread, ( lock, ) )
  1229.     gobject.timeout_add( 500, main_radar_window.update_plist_items )
  1230.     main_radar_window.main()
  1231.  
  1232.  
  1233. ####################################################################################################
  1234. # Initializers
  1235. access_points        = {}
  1236. auto_profile_order    = []
  1237. lock                = None
  1238. s                    = None
  1239. #sys.setcheckinterval( 100 )
  1240. # First load our conf file and know profiles
  1241. confFile            = ConfigParser.ConfigParser()
  1242. if not os.path.isfile( CONF_FILE ):
  1243.     # No config file exists, build one real quick
  1244.     confFile.set("DEFAULT", "interface", INTERFACE )
  1245.     confFile.set("DEFAULT", "scan_timeout", SCAN_TIMEOUT )
  1246.     confFile.set("DEFAULT", "speak_up", SPEAK_UP )
  1247.     confFile.set("DEFAULT", "commit_required", COMMIT_REQUIRED )
  1248.     confFile.set("DEFAULT", "ifup_required", IFUP_REQUIRED )
  1249.     confFile.set("DEFAULT", "auto_profile_order", '' )
  1250.     confFile.write( open( CONF_FILE, "w" ) )
  1251. else:
  1252.     confFile.readfp( open( CONF_FILE ) )
  1253.     # Override the defaults
  1254.     try: INTERFACE        = confFile.get            ( "DEFAULT", "interface" )
  1255.     except: confFile.set("DEFAULT", "interface", INTERFACE )
  1256.     try: SCAN_TIMEOUT    = confFile.getint        ( "DEFAULT", "scan_timeout" )
  1257.     except: confFile.set("DEFAULT", "scan_timeout", SCAN_TIMEOUT )
  1258.     try: SPEAK_UP        = confFile.getboolean    ( "DEFAULT", "speak_up" )
  1259.     except: confFile.set("DEFAULT", "speak_up", SPEAK_UP )
  1260.     try: COMMIT_REQUIRED= confFile.getboolean    ( "DEFAULT", "commit_required" )
  1261.     except: confFile.set("DEFAULT", "commit_required", COMMIT_REQUIRED )
  1262.     try: IFUP_REQUIRED= confFile.getboolean    ( "DEFAULT", "ifup_required" )
  1263.     except: confFile.set("DEFAULT", "ifup_required", IFUP_REQUIRED )
  1264.     try: auto_profile_order    = confFile.get    ( "DEFAULT", "auto_profile_order" )
  1265.     except: confFile.set("DEFAULT", "auto_profile_order", auto_profile_order )
  1266.     # convert the auto_profile_order to a list for ordering
  1267.     if auto_profile_order == '':
  1268.         auto_profile_order = []
  1269.     else:
  1270.         auto_profile_order = auto_profile_order.split( ',' )
  1271.     # First, we add our known profiles
  1272.     for apname in confFile.sections():
  1273.         ap = {}
  1274.         # set the defaults
  1275.         ap['known']        = True
  1276.         ap['available']    = False
  1277.         ap['encrypted'] = False
  1278.         ap['mode']        = ''
  1279.         ap['security']    = ''
  1280.         ap['channel']    = ''
  1281.         ap['protocol']    = 'g'
  1282.         ap['signal']    = '0'
  1283.         ap['prescript']    = ''
  1284.         ap['postscript']= ''
  1285.         # read the important values
  1286.         if confFile.has_option( apname, 'key'):
  1287.             if len( confFile.get( apname, 'key' ) ) > 0:
  1288.                 ap['encrypted'] = True
  1289.         if confFile.has_option( apname, 'mode'):
  1290.             apmode = confFile.get( apname, 'mode' )
  1291.             if len( apmode ) > 0:
  1292.                 ap['mode'] = apmode
  1293.         if confFile.has_option( apname, 'security'):
  1294.             apsec = confFile.get( apname, 'security' )
  1295.             if len( apsec ) > 0:
  1296.                 ap['security'] = apsec
  1297.         if confFile.has_option( apname, 'channel'):
  1298.             apchan = confFile.get( apname, 'channel' )
  1299.             if len( apchan ) > 0:
  1300.                 ap['channel'] = apchan
  1301.         if confFile.has_option( apname, 'protocol'):
  1302.             approt = confFile.get( apname, 'protocol' )
  1303.             if len( approt ) > 0:
  1304.                 ap['protocol'] = approt
  1305.         #~ if confFile.has_option( apname, 'prescript'):
  1306.             #~ prescript = confFile.get( apname, 'prescript' )
  1307.             #~ if len( prescript ) > 0:
  1308.                 #~ ap['prescript'] = prescript
  1309.         #~ if confFile.has_option( apname, 'postscript'):
  1310.             #~ postscript = confFile.get( apname, 'postscript' )
  1311.             #~ if len( postscript ) > 0:
  1312.                 #~ ap['postscript'] = postscript
  1313.         #~ if confFile.has_option( apname, 'use_wpa'):
  1314.             #~ postscript = confFile.get( apname, 'postscript' )
  1315.             #~ if len( postscript ) > 0:
  1316.                 #~ ap['postscript'] = postscript
  1317.         #
  1318.         access_points[ apname ] = ap
  1319.         # if it is not in the auto_profile_order add it
  1320.         if not apname in auto_profile_order:
  1321.             auto_profile_order.append( apname )
  1322. ####################################################################################################
  1323. # Embedded Images
  1324. wifi_radar_icon = [ ""
  1325.   "GdkP"
  1326.   "\0\0\22""7"
  1327.   "\2\1\0\2"
  1328.   "\0\0\1\214"
  1329.   "\0\0\0c"
  1330.   "\0\0\0O"
  1331.   "\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0\377\377\377\377"
  1332.   "\0\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0\261\377\377"
  1333.   "\377\0\7\0\0\0\10\0\0\0\25\0\0\0\35\0\0\0%\0\0\0-\0\0\0\"\0\0\0\11\327"
  1334.   "\377\377\377\0\6\0\0\0\"\0\0\0_\0\0\0\213\0\0\0\266\0\0\0\341\0\0\0\376"
  1335.   "\206\0\0\0\377\6\0\0\0\356\0\0\0\324\0\0\0\265\0\0\0~\0\0\0@\0\0\0\10"
  1336.   "\315\377\377\377\0\4\0\0\0\2\0\0\0;\0\0\0\210\0\0\0\325\221\0\0\0\377"
  1337.   "\4\0\0\0\371\0\0\0\303\0\0\0w\0\0\0\31\310\377\377\377\0\3\0\0\0\6\0"
  1338.   "\0\0m\0\0\0\342\227\0\0\0\377\4\0\0\0\374\0\0\0\264\0\0\0Q\0\0\0\5\303"
  1339.   "\377\377\377\0\3\0\0\0\4\0\0\0d\0\0\0\341\234\0\0\0\377\3\0\0\0\341\0"
  1340.   "\0\0`\0\0\0\2\277\377\377\377\0\3\0\0\0\2\0\0\0[\0\0\0\333\240\0\0\0"
  1341.   "\377\2\0\0\0\323\0\0\0K\274\377\377\377\0\3\0\0\0\1\0\0\0R\0\0\0\324"
  1342.   "\244\0\0\0\377\2\0\0\0\276\0\0\0#\271\377\377\377\0\2\0\0\0\31\0\0\0"
  1343.   "\277\247\0\0\0\377\2\0\0\0\363\0\0\0c\267\377\377\377\0\2\0\0\0/\0\0"
  1344.   "\0\343\252\0\0\0\377\2\0\0\0\257\0\0\0\24\264\377\377\377\0\2\0\0\0M"
  1345.   "\0\0\0\363\220\0\0\0\377\14\0\0\0\357\0\0\0\304\0\0\0\230\0\0\0v\0\0"
  1346.   "\0l\0\0\0c\0\0\0[\0\0\0j\0\0\0\205\0\0\0\240\0\0\0\311\0\0\0\373\220"
  1347.   "\0\0\0\377\2\0\0\0\346\0\0\0""4\262\377\377\377\0\2\0\0\0q\0\0\0\375"
  1348.   "\215\0\0\0\377\4\0\0\0\373\0\0\0\300\0\0\0t\0\0\0)\213\377\377\377\0"
  1349.   "\4\0\0\0\14\0\0\0E\0\0\0\205\0\0\0\334\216\0\0\0\377\2\0\0\0\363\0\0"
  1350.   "\0D\257\377\377\377\0\2\0\0\0\4\0\0\0\230\215\0\0\0\377\3\0\0\0\372\0"
  1351.   "\0\0\231\0\0\0\34\221\377\377\377\0\4\0\0\0\1\0\0\0C\0\0\0\251\0\0\0"
  1352.   "\372\214\0\0\0\377\2\0\0\0\371\0\0\0W\255\377\377\377\0\2\0\0\0\17\0"
  1353.   "\0\0\272\214\0\0\0\377\3\0\0\0\375\0\0\0\241\0\0\0\"\226\377\377\377"
  1354.   "\0\2\0\0\0\"\0\0\0\252\214\0\0\0\377\2\0\0\0\375\0\0\0k\253\377\377\377"
  1355.   "\0\2\0\0\0\25\0\0\0\324\213\0\0\0\377\3\0\0\0\376\0\0\0\252\0\0\0(\232"
  1356.   "\377\377\377\0\2\0\0\0""9\0\0\0\312\214\0\0\0\377\1\0\0\0\200\251\377"
  1357.   "\377\377\0\2\0\0\0\5\0\0\0\303\213\0\0\0\377\2\0\0\0\332\0\0\0""1\235"
  1358.   "\377\377\377\0\3\0\0\0\4\0\0\0\201\0\0\0\374\213\0\0\0\377\1\0\0\0p\250"
  1359.   "\377\377\377\0\1\0\0\0\222\213\0\0\0\377\2\0\0\0\301\0\0\0\22\240\377"
  1360.   "\377\377\0\2\0\0\0:\0\0\0\336\212\0\0\0\377\2\0\0\0\374\0\0\0I\246\377"
  1361.   "\377\377\0\1\0\0\0[\213\0\0\0\377\2\0\0\0\241\0\0\0\6\212\377\377\377"
  1362.   "\0\15\0\0\0\2\0\0\0&\0\0\0U\0\0\0\203\0\0\0\242\0\0\0\243\0\0\0\234\0"
  1363.   "\0\0\225\0\0\0\215\0\0\0\206\0\0\0}\0\0\0\\\0\0\0!\213\377\377\377\0"
  1364.   "\2\0\0\0\22\0\0\0\307\212\0\0\0\377\2\0\0\0\361\0\0\0+\244\377\377\377"
  1365.   "\0\2\0\0\0.\0\0\0\365\211\0\0\0\377\2\0\0\0\376\0\0\0|\211\377\377\377"
  1366.   "\0\4\0\0\0#\0\0\0d\0\0\0\223\0\0\0\277\214\0\0\0\310\4\0\0\0\253\0\0"
  1367.   "\0l\0\0\0-\0\0\0\2\210\377\377\377\0\2\0\0\0\12\0\0\0\267\212\0\0\0\377"
  1368.   "\2\0\0\0\336\0\0\0\24\242\377\377\377\0\2\0\0\0\20\0\0\0\334\211\0\0"
  1369.   "\0\377\2\0\0\0\367\0\0\0W\210\377\377\377\0\2\0\0\0#\0\0\0\211\223\0"
  1370.   "\0\0\310\3\0\0\0\266\0\0\0t\0\0\0\27\207\377\377\377\0\2\0\0\0\5\0\0"
  1371.   "\0\244\212\0\0\0\377\2\0\0\0\302\0\0\0\6\240\377\377\377\0\2\0\0\0\1"
  1372.   "\0\0\0\264\211\0\0\0\377\2\0\0\0\363\0\0\0""9\207\377\377\377\0\3\0\0"
  1373.   "\0\34\0\0\0\201\0\0\0\306\226\0\0\0\310\3\0\0\0\277\0\0\0Y\0\0\0\2\206"
  1374.   "\377\377\377\0\2\0\0\0\1\0\0\0\217\212\0\0\0\377\1\0\0\0\203\240\377"
  1375.   "\377\377\0\1\0\0\0\177\212\0\0\0\377\1\0\0\0T\206\377\377\377\0\3\0\0"
  1376.   "\0\25\0\0\0z\0\0\0\305\232\0\0\0\310\2\0\0\0\242\0\0\0*\207\377\377\377"
  1377.   "\0\1\0\0\0\243\211\0\0\0\377\2\0\0\0\372\0\0\0,\236\377\377\377\0\2\0"
  1378.   "\0\0D\0\0\0\375\211\0\0\0\377\1\0\0\0\213\206\377\377\377\0\2\0\0\0""8"
  1379.   "\0\0\0\274\235\0\0\0\310\3\0\0\0\306\0\0\0u\0\0\0\14\205\377\377\377"
  1380.   "\0\2\0\0\0\7\0\0\0\306\211\0\0\0\377\2\0\0\0\306\0\0\0\2\234\377\377"
  1381.   "\377\0\2\0\0\0\4\0\0\0\331\211\0\0\0\377\2\0\0\0\276\0\0\0\3\205\377"
  1382.   "\377\377\0\2\0\0\0T\0\0\0\306\214\0\0\0\310\10\0\0\0\260\0\0\0\202\0"
  1383.   "\0\0v\0\0\0~\0\0\0\207\0\0\0\217\0\0\0\227\0\0\0\264\214\0\0\0\310\2"
  1384.   "\0\0\0\264\0\0\0""2\205\377\377\377\0\2\0\0\0\27\0\0\0\341\211\0\0\0"
  1385.   "\377\1\0\0\0k\234\377\377\377\0\1\0\0\0c\211\0\0\0\377\2\0\0\0\343\0"
  1386.   "\0\0\26\204\377\377\377\0\2\0\0\0\2\0\0\0s\212\0\0\0\310\4\0\0\0\265"
  1387.   "\0\0\0s\0\0\0D\0\0\0\26\207\377\377\377\0\4\0\0\0\1\0\0\0+\0\0\0j\0\0"
  1388.   "\0\250\212\0\0\0\310\2\0\0\0\303\0\0\0A\205\377\377\377\0\2\0\0\0/\0"
  1389.   "\0\0\364\210\0\0\0\377\2\0\0\0\362\0\0\0\33\232\377\377\377\0\2\0\0\0"
  1390.   "\7\0\0\0\341\210\0\0\0\377\2\0\0\0\371\0\0\0""7\204\377\377\377\0\2\0"
  1391.   "\0\0\12\0\0\0\217\211\0\0\0\310\3\0\0\0\271\0\0\0]\0\0\0\10\216\377\377"
  1392.   "\377\0\3\0\0\0\36\0\0\0t\0\0\0\306\210\0\0\0\310\2\0\0\0\306\0\0\0P\205"
  1393.   "\377\377\377\0\1\0\0\0a\211\0\0\0\377\1\0\0\0\257\232\377\377\377\0\1"
  1394.   "\0\0\0n\211\0\0\0\377\1\0\0\0h\204\377\377\377\0\2\0\0\0\20\0\0\0\245"
  1395.   "\210\0\0\0\310\3\0\0\0\274\0\0\0c\0\0\0\12\222\377\377\377\0\2\0\0\0"
  1396.   "*\0\0\0\242\211\0\0\0\310\1\0\0\0`\205\377\377\377\0\1\0\0\0\276\211"
  1397.   "\0\0\0\377\1\0\0\0:\230\377\377\377\0\2\0\0\0\13\0\0\0\350\210\0\0\0"
  1398.   "\377\1\0\0\0\250\204\377\377\377\0\2\0\0\0\3\0\0\0\230\210\0\0\0\310"
  1399.   "\2\0\0\0\213\0\0\0\15\225\377\377\377\0\3\0\0\0\2\0\0\0Z\0\0\0\277\210"
  1400.   "\0\0\0\310\1\0\0\0U\204\377\377\377\0\2\0\0\0%\0\0\0\370\210\0\0\0\377"
  1401.   "\1\0\0\0\265\230\377\377\377\0\1\0\0\0y\210\0\0\0\377\2\0\0\0\372\0\0"
  1402.   "\0\40\204\377\377\377\0\1\0\0\0o\210\0\0\0\310\2\0\0\0o\0\0\0\2\230\377"
  1403.   "\377\377\0\2\0\0\0\30\0\0\0\226\207\0\0\0\310\2\0\0\0\306\0\0\0""7\204"
  1404.   "\377\377\377\0\1\0\0\0|\211\0\0\0\377\1\0\0\0""0\226\377\377\377\0\2"
  1405.   "\0\0\0\20\0\0\0\356\210\0\0\0\377\1\0\0\0\226\204\377\377\377\0\1\0\0"
  1406.   "\0C\207\0\0\0\310\2\0\0\0\305\0\0\0R\233\377\377\377\0\2\0\0\0\5\0\0"
  1407.   "\0\210\207\0\0\0\310\2\0\0\0\273\0\0\0\37\203\377\377\377\0\2\0\0\0\6"
  1408.   "\0\0\0\325\210\0\0\0\377\1\0\0\0\251\226\377\377\377\0\1\0\0\0\204\210"
  1409.   "\0\0\0\377\2\0\0\0\366\0\0\0\32\203\377\377\377\0\2\0\0\0!\0\0\0\277"
  1410.   "\206\0\0\0\310\2\0\0\0\275\0\0\0""8\235\377\377\377\0\2\0\0\0\2\0\0\0"
  1411.   "|\207\0\0\0\310\2\0\0\0\254\0\0\0\15\203\377\377\377\0\1\0\0\0J\210\0"
  1412.   "\0\0\377\2\0\0\0\375\0\0\0&\224\377\377\377\0\2\0\0\0\26\0\0\0\364\210"
  1413.   "\0\0\0\377\1\0\0\0\214\203\377\377\377\0\2\0\0\0\12\0\0\0\251\206\0\0"
  1414.   "\0\310\2\0\0\0\305\0\0\0""0\240\377\377\377\0\1\0\0\0r\207\0\0\0\310"
  1415.   "\1\0\0\0[\204\377\377\377\0\1\0\0\0\317\210\0\0\0\377\1\0\0\0\236\224"
  1416.   "\377\377\377\0\1\0\0\0\204\210\0\0\0\377\2\0\0\0\362\0\0\0\24\203\377"
  1417.   "\377\377\0\1\0\0\0\206\207\0\0\0\310\1\0\0\0X\214\377\377\377\0\11\0"
  1418.   "\0\0\5\0\0\0$\0\0\0G\0\0\0X\0\0\0T\0\0\0O\0\0\0K\0\0\0B\0\0\0\35\214"
  1419.   "\377\377\377\0\2\0\0\0\2\0\0\0\214\206\0\0\0\310\2\0\0\0\307\0\0\0""1"
  1420.   "\203\377\377\377\0\1\0\0\0V\210\0\0\0\377\2\0\0\0\372\0\0\0\27\223\377"
  1421.   "\377\377\0\1\0\0\0\271\210\0\0\0\377\1\0\0\0\202\203\377\377\377\0\1"
  1422.   "\0\0\0@\207\0\0\0\310\1\0\0\0\204\212\377\377\377\0\4\0\0\0\7\0\0\0E"
  1423.   "\0\0\0u\0\0\0\222\210\0\0\0\226\4\0\0\0\204\0\0\0T\0\0\0$\0\0\0\1\211"
  1424.   "\377\377\377\0\2\0\0\0\12\0\0\0\245\206\0\0\0\310\2\0\0\0\251\0\0\0\5"
  1425.   "\202\377\377\377\0\2\0\0\0\2\0\0\0\331\210\0\0\0\377\1\0\0\0C\223\377"
  1426.   "\377\377\0\1\0\0\0\342\207\0\0\0\377\2\0\0\0\356\0\0\0\17\202\377\377"
  1427.   "\377\0\2\0\0\0\2\0\0\0\246\206\0\0\0\310\2\0\0\0\246\0\0\0\11\210\377"
  1428.   "\377\377\0\3\0\0\0\5\0\0\0D\0\0\0\212\216\0\0\0\226\2\0\0\0z\0\0\0\40"
  1429.   "\211\377\377\377\0\2\0\0\0\32\0\0\0\274\206\0\0\0\310\1\0\0\0d\203\377"
  1430.   "\377\377\0\1\0\0\0a\210\0\0\0\377\1\0\0\0b\222\377\377\377\0\2\0\0\0"
  1431.   "\10\0\0\0\375\207\0\0\0\377\1\0\0\0x\203\377\377\377\0\1\0\0\0G\206\0"
  1432.   "\0\0\310\2\0\0\0\275\0\0\0\36\210\377\377\377\0\2\0\0\0""3\0\0\0\207"
  1433.   "\221\0\0\0\226\3\0\0\0\225\0\0\0X\0\0\0\11\210\377\377\377\0\1\0\0\0"
  1434.   "R\206\0\0\0\310\2\0\0\0\302\0\0\0\23\202\377\377\377\0\2\0\0\0\5\0\0"
  1435.   "\0\342\207\0\0\0\377\1\0\0\0\201\223\377\377\377\0\1\0\0\0m\206\0\0\0"
  1436.   "\377\2\0\0\0\321\0\0\0\12\202\377\377\377\0\2\0\0\0\3\0\0\0\254\206\0"
  1437.   "\0\0\310\1\0\0\0J\207\377\377\377\0\2\0\0\0\1\0\0\0O\210\0\0\0\226\1"
  1438.   "\0\0\0\206\202\0\0\0h\3\0\0\0m\0\0\0s\0\0\0\214\207\0\0\0\226\2\0\0\0"
  1439.   "\210\0\0\0)\207\377\377\377\0\2\0\0\0\1\0\0\0\233\206\0\0\0\310\1\0\0"
  1440.   "\0l\203\377\377\377\0\2\0\0\0P\0\0\0\374\205\0\0\0\377\2\0\0\0\337\0"
  1441.   "\0\0\"\224\377\377\377\0\1\0\0\0s\204\0\0\0\377\2\0\0\0\315\0\0\0\23"
  1442.   "\203\377\377\377\0\1\0\0\0N\206\0\0\0\310\2\0\0\0\245\0\0\0\2\206\377"
  1443.   "\377\377\0\2\0\0\0\6\0\0\0f\206\0\0\0\226\3\0\0\0w\0\0\0""7\0\0\0\23"
  1444.   "\205\377\377\377\0\4\0\0\0\3\0\0\0*\0\0\0[\0\0\0\212\205\0\0\0\226\2"
  1445.   "\0\0\0\222\0\0\0*\207\377\377\377\0\2\0\0\0#\0\0\0\304\205\0\0\0\310"
  1446.   "\2\0\0\0\277\0\0\0\16\203\377\377\377\0\2\0\0\0]\0\0\0\376\203\0\0\0"
  1447.   "\377\2\0\0\0\332\0\0\0\35\226\377\377\377\0\5\0\0\0;\0\0\0j\0\0\0\223"
  1448.   "\0\0\0\244\0\0\0\20\203\377\377\377\0\2\0\0\0\5\0\0\0\260\206\0\0\0\310"
  1449.   "\1\0\0\0>\206\377\377\377\0\2\0\0\0\14\0\0\0z\205\0\0\0\226\2\0\0\0|"
  1450.   "\0\0\0/\213\377\377\377\0\3\0\0\0\10\0\0\0U\0\0\0\224\204\0\0\0\226\2"
  1451.   "\0\0\0\221\0\0\0%\207\377\377\377\0\1\0\0\0s\206\0\0\0\310\1\0\0\0d\204"
  1452.   "\377\377\377\0\5\0\0\0a\0\0\0\240\0\0\0\177\0\0\0]\0\0\0\26\237\377\377"
  1453.   "\377\0\1\0\0\0U\206\0\0\0\310\1\0\0\0\235\206\377\377\377\0\2\0\0\0\2"
  1454.   "\0\0\0r\204\0\0\0\226\3\0\0\0\225\0\0\0J\0\0\0\1\216\377\377\377\0\2"
  1455.   "\0\0\0\35\0\0\0w\204\0\0\0\226\2\0\0\0\217\0\0\0\40\206\377\377\377\0"
  1456.   "\2\0\0\0\27\0\0\0\304\205\0\0\0\310\2\0\0\0\273\0\0\0\12\247\377\377"
  1457.   "\377\0\1\0\0\0\236\206\0\0\0\310\1\0\0\0""5\206\377\377\377\0\1\0\0\0"
  1458.   "T\204\0\0\0\226\2\0\0\0\221\0\0\0""3\221\377\377\377\0\2\0\0\0\4\0\0"
  1459.   "\0l\204\0\0\0\226\2\0\0\0\215\0\0\0\34\206\377\377\377\0\1\0\0\0}\206"
  1460.   "\0\0\0\310\1\0\0\0E\247\377\377\377\0\1\0\0\0\276\205\0\0\0\310\1\0\0"
  1461.   "\0\224\206\377\377\377\0\1\0\0\0""4\204\0\0\0\226\2\0\0\0\214\0\0\0\40"
  1462.   "\223\377\377\377\0\2\0\0\0\5\0\0\0q\204\0\0\0\226\2\0\0\0\211\0\0\0\14"
  1463.   "\205\377\377\377\0\2\0\0\0\37\0\0\0\306\205\0\0\0\310\1\0\0\0`\246\377"
  1464.   "\377\377\0\2\0\0\0\12\0\0\0\277\205\0\0\0\310\1\0\0\0+\205\377\377\377"
  1465.   "\0\2\0\0\0\30\0\0\0\220\203\0\0\0\226\2\0\0\0\225\0\0\0*\225\377\377"
  1466.   "\377\0\2\0\0\0\10\0\0\0v\204\0\0\0\226\1\0\0\0X\206\377\377\377\0\1\0"
  1467.   "\0\0\207\205\0\0\0\310\1\0\0\0m\247\377\377\377\0\2\0\0\0""3\0\0\0\301"
  1468.   "\203\0\0\0\310\1\0\0\0[\206\377\377\377\0\1\0\0\0n\204\0\0\0\226\1\0"
  1469.   "\0\0G\227\377\377\377\0\2\0\0\0\12\0\0\0z\203\0\0\0\226\2\0\0\0\224\0"
  1470.   "\0\0\27\205\377\377\377\0\2\0\0\0\20\0\0\0\246\203\0\0\0\310\2\0\0\0"
  1471.   "\224\0\0\0\11\250\377\377\377\0\4\0\0\0,\0\0\0h\0\0\0\210\0\0\0R\206"
  1472.   "\377\377\377\0\1\0\0\0&\204\0\0\0\226\2\0\0\0f\0\0\0\1\230\377\377\377"
  1473.   "\0\2\0\0\0\26\0\0\0\224\203\0\0\0\226\1\0\0\0g\206\377\377\377\0\5\0"
  1474.   "\0\0\22\0\0\0\206\0\0\0y\0\0\0]\0\0\0\6\263\377\377\377\0\1\0\0\0t\203"
  1475.   "\0\0\0\226\2\0\0\0\216\0\0\0\13\232\377\377\377\0\1\0\0\0X\204\0\0\0"
  1476.   "\226\1\0\0\0#\274\377\377\377\0\1\0\0\0-\204\0\0\0\226\1\0\0\0K\233\377"
  1477.   "\377\377\0\2\0\0\0\15\0\0\0\217\203\0\0\0\226\1\0\0\0v\274\377\377\377"
  1478.   "\0\1\0\0\0t\203\0\0\0\226\2\0\0\0\213\0\0\0\10\213\377\377\377\0\5\0"
  1479.   "\0\0\5\0\0\0\30\0\0\0\40\0\0\0\36\0\0\0\22\214\377\377\377\0\1\0\0\0"
  1480.   "J\204\0\0\0\226\1\0\0\0*\273\377\377\377\0\1\0\0\0`\203\0\0\0\226\1\0"
  1481.   "\0\0E\212\377\377\377\0\3\0\0\0\13\0\0\0@\0\0\0Y\204\0\0\0Z\3\0\0\0Q"
  1482.   "\0\0\0""1\0\0\0\5\211\377\377\377\0\2\0\0\0\6\0\0\0\207\203\0\0\0\226"
  1483.   "\1\0\0\0\26\273\377\377\377\0\5\0\0\0""1\0\0\0\226\0\0\0\224\0\0\0n\0"
  1484.   "\0\0\5\211\377\377\377\0\2\0\0\0$\0\0\0U\202\0\0\0Z\4\0\0\0P\0\0\0E\0"
  1485.   "\0\0I\0\0\0X\202\0\0\0Z\2\0\0\0P\0\0\0\33\211\377\377\377\0\4\0\0\0""3"
  1486.   "\0\0\0\206\0\0\0\226\0\0\0\201\274\377\377\377\0\3\0\0\0\6\0\0\0""8\0"
  1487.   "\0\0\13\211\377\377\377\0\2\0\0\0\7\0\0\0A\202\0\0\0Z\2\0\0\0I\0\0\0"
  1488.   "\20\203\377\377\377\0\6\0\0\0\4\0\0\0\37\0\0\0O\0\0\0Z\0\0\0Y\0\0\0\36"
  1489.   "\212\377\377\377\0\2\0\0\0\34\0\0\0)\310\377\377\377\0\5\0\0\0<\0\0\0"
  1490.   "Z\0\0\0Y\0\0\0.\0\0\0\2\206\377\377\377\0\5\0\0\0\3\0\0\0;\0\0\0Z\0\0"
  1491.   "\0X\0\0\0\32\322\377\377\377\0\1\0\0\0\34\202\0\0\0Z\1\0\0\0\30\211\377"
  1492.   "\377\377\0\5\0\0\0\1\0\0\0>\0\0\0Z\0\0\0W\0\0\0\13\320\377\377\377\0"
  1493.   "\4\0\0\0\5\0\0\0P\0\0\0Z\0\0\0""5\213\377\377\377\0\4\0\0\0\2\0\0\0H"
  1494.   "\0\0\0Z\0\0\0:\320\377\377\377\0\4\0\0\0""4\0\0\0Z\0\0\0P\0\0\0\5\214"
  1495.   "\377\377\377\0\1\0\0\0\26\202\0\0\0Z\1\0\0\0\22\317\377\377\377\0\3\0"
  1496.   "\0\0+\0\0\0X\0\0\0\33\216\377\377\377\0\3\0\0\0>\0\0\0I\0\0\0\23\320"
  1497.   "\377\377\377\0\1\0\0\0\12\217\377\377\377\0\2\0\0\0\6\0\0\0\1\377\377"
  1498.   "\377\377\0\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0\377"
  1499.   "\377\377\377\0\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0"
  1500.   "\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0\234\377\377\377"
  1501.   "\0"]
  1502.  
  1503. known_profile_icon = [ ""
  1504.   "GdkP"
  1505.   "\0\0\5""0"
  1506.   "\2\1\0\2"
  1507.   "\0\0\0P"
  1508.   "\0\0\0\24"
  1509.   "\0\0\0\24"
  1510.   "\210\0\0\0\0\4\0\0\0\3\0\0\0\16\0\0\0\23\0\0\0\11\216\0\0\0\0\11\0\0"
  1511.   "\0\16\0\0\0h\0\0\0\301\0\0\0\345\0\0\0\352\0\0\0\331\0\0\0\237\0\0\0"
  1512.   "9\0\0\0\3\212\0\0\0\0\13\0\0\0@\0\0\0\323\0\0\0\376\0\0\0\350\0\0\0\304"
  1513.   "\0\0\0\271\0\0\0\323\0\0\0\367\0\0\0\370\0\0\0\227\0\0\0\17\210\0\0\0"
  1514.   "\0\15\0\0\0K\0\0\0\354\0\0\0\365\0\0\0\206\0\0\0#\0\0\0\6\0\0\0\3\0\0"
  1515.   "\0\15\0\0\0C\0\0\0\304\0\0\0\376\0\0\0\260\0\0\0\22\206\0\0\0\0\17\0"
  1516.   "\0\0""2\0\0\0\346\0\0\0\351\0\0\0L\0\0\0#\0\0\0u\0\0\0\246\0\0\0\257"
  1517.   "\0\0\0\223\0\0\0M\0\0\0\27\0\0\0\235\0\0\0\375\0\0\0\242\0\0\0\7\204"
  1518.   "\0\0\0\0\20\0\0\0\13\0\0\0\300\0\0\0\372\0\0\0W\0\0\0O\0\0\0\271\0\0"
  1519.   "\0\233\0\0\0b\0\0\0V\0\0\0z\0\0\0\267\0\0\0\223\0\0\0$\0\0\0\267\0\0"
  1520.   "\0\374\0\0\0X\204\0\0\0\0\7\0\0\0S\0\0\0\374\0\0\0\240\0\0\0H\0\0\0\275"
  1521.   "\0\0\0a\0\0\0\12\202\0\0\0\0\10\0\0\0\1\0\0\0%\0\0\0\240\0\0\0\241\0"
  1522.   "\0\0""9\0\0\0\352\0\0\0\320\0\0\0\12\203\0\0\0\0\21\0\0\0\262\0\0\0\351"
  1523.   "\0\0\0A\0\0\0\272\0\0\0g\0\0\0\6\0\0\0""4\0\0\0e\0\0\0l\0\0\0T\0\0\0"
  1524.   "\25\0\0\0\27\0\0\0\251\0\0\0v\0\0\0\214\0\0\0\367\0\0\0<\203\0\0\0\0"
  1525.   "\21\0\0\0""6\0\0\0G\0\0\0r\0\0\0\244\0\0\0\17\0\0\0P\0\0\0b\0\0\0#\0"
  1526.   "\0\0\27\0\0\0;\0\0\0s\0\0\0\33\0\0\0E\0\0\0\270\0\0\0""6\0\0\0\\\0\0"
  1527.   "\0\15\205\0\0\0\0\15\0\0\0T\0\0\0""8\0\0\0""0\0\0\0f\0\0\0\6\0\0\0\0"
  1528.   "\0\0\0\1\0\0\0\0\0\0\0(\0\0\0l\0\0\0\13\0\0\0k\0\0\0\33\206\0\0\0\0\16"
  1529.   "***;\210\210\210\356\223\223\223\377iii\377\204\204\204\377\216\216\216"
  1530.   "\377~~~\377zzz\377\203\203\203\377\215\215\215\377ddd\377\202\202\202"
  1531.   "\377xxx\356\40\40\40;\205\0\0\0\0\2&&&#\251\251\251\353\202\374\374\374"
  1532.   "\377\202\372\372\372\377\5\335\335\335\377\353\353\353\377\366\366\366"
  1533.   "\377\327\327\327\377\357\357\357\377\202\365\365\365\377\3\362\362\362"
  1534.   "\377\226\226\226\353\27\27\27)\204\0\0\0\0\21,,,p\354\354\354\377\355"
  1535.   "\355\355\377\351\351\351\377\346\346\346\377\342\342\342\377\335\335"
  1536.   "\335\377\334\334\334\377\330\330\330\377\324\324\324\377\320\320\320"
  1537.   "\377\316\316\316\377\313\313\313\377\307\307\307\377\314\314\314\377"
  1538.   "\35\35\35y\0\0\0\1\202\0\0\0\0\14\0\0\0\2(((\203\357\357\357\377\345"
  1539.   "\345\345\377\341\341\341\377\337\337\337\377\333\333\333\377\326\326"
  1540.   "\326\377\322\322\322\377\316\316\316\377\312\312\312\377\306\306\306"
  1541.   "\377\202\302\302\302\377\30\314\314\314\377\311\311\311\377\33\33\33"
  1542.   "\204\0\0\0\5\0\0\0\1\0\0\0\2\0\0\0\10&&&\210\356\356\356\377\342\342"
  1543.   "\342\377\347\347\347\377\346\346\346\377\324GG\377\337\337\337\377\324"
  1544.   "GG\377\333\322\322\377\324GG\377<\341@\377\324GG\377<\341@\377\321\321"
  1545.   "\321\377\276\276\276\377\27\27\27\214\0\0\0\15\202\0\0\0\4+\0\0\0\21"
  1546.   "$$$\221\355\355\355\377\345\345\345\377\344\344\344\377\340\340\340\377"
  1547.   "\334\334\334\377\331\331\331\377\325\325\325\377\321\321\321\377\316"
  1548.   "\316\316\377\312\312\312\377\306\306\306\377\307\307\307\377\313\313"
  1549.   "\313\377\272\272\272\377\24\24\24\226\0\0\0\30\0\0\0\10\0\0\0\5\0\0\0"
  1550.   "\27\"\"\"\231\354\354\354\377\346\346\346\377\342\342\342\377\337\337"
  1551.   "\337\377\333\333\333\377\327\327\327\377\324\324\324\377\320\320\320"
  1552.   "\377\314\314\314\377\310\310\310\377\305\305\305\377\301\301\301\377"
  1553.   "\276\276\276\377\271\271\271\377\23\23\23\235\0\0\0\35\0\0\0\10\0\0\0"
  1554.   "\4\0\0\0\32\40\40\40\223\310\310\310\376\202\274\274\274\377\4\272\272"
  1555.   "\272\377\271\271\271\377\270\270\270\377\267\267\267\377\202\271\271"
  1556.   "\271\377\16\270\270\270\377\266\266\266\377\265\265\265\377\264\264\264"
  1557.   "\377\231\231\231\376\16\16\16\240\0\0\0\35\0\0\0\6\0\0\0\2\0\0\0\12\0"
  1558.   "\0\0/\0\0\0n\0\0\0|\0\0\0\177\202\0\0\0\200\202\0\0\0\201\1\0\0\0\203"
  1559.   "\204\0\0\0\205\12\0\0\0\201\0\0\0y\0\0\0<\0\0\0\15\0\0\0\2\0\0\0\0\0"
  1560.   "\0\0\2\0\0\0\6\0\0\0\14\0\0\0\20\204\0\0\0\24\202\0\0\0\25\203\0\0\0"
  1561.   "\26\6\0\0\0\25\0\0\0\22\0\0\0\15\0\0\0\7\0\0\0\2\0\0\0\0"]
  1562.  
  1563. unknown_profile_icon = [ ""
  1564.   "GdkP"
  1565.   "\0\0\5\22"
  1566.   "\2\1\0\2"
  1567.   "\0\0\0P"
  1568.   "\0\0\0\24"
  1569.   "\0\0\0\24"
  1570.   "\210\0\0\0\0\4\0\0\0\1\0\0\0\4\0\0\0\6\0\0\0\3\216\0\0\0\0\11\0\0\0\4"
  1571.   "\0\0\0\37\0\0\0""9\0\0\0D\0\0\0F\0\0\0@\0\0\0/\0\0\0\21\0\0\0\1\212\0"
  1572.   "\0\0\0\7\0\0\0\23\0\0\0\77\0\0\0K\0\0\0E\0\0\0:\0\0\0""7\0\0\0\77\202"
  1573.   "\0\0\0I\2\0\0\0-\0\0\0\4\210\0\0\0\0\15\0\0\0\26\0\0\0F\0\0\0I\0\0\0"
  1574.   "(\0\0\0\13\0\0\0\2\0\0\0\1\0\0\0\4\0\0\0\24\0\0\0:\0\0\0K\0\0\0""4\0"
  1575.   "\0\0\6\206\0\0\0\0\17\0\0\0\17\0\0\0D\0\0\0E\0\0\0\26\0\0\0\13\0\0\0"
  1576.   "#\0\0\0""1\0\0\0""4\0\0\0,\0\0\0\27\0\0\0\7\0\0\0/\0\0\0K\0\0\0""0\0"
  1577.   "\0\0\2\204\0\0\0\0\20\0\0\0\3\0\0\0""9\0\0\0J\0\0\0\32\0\0\0\30\0\0\0"
  1578.   "7\0\0\0.\0\0\0\35\0\0\0\32\0\0\0$\0\0\0""6\0\0\0,\0\0\0\13\0\0\0""6\0"
  1579.   "\0\0K\0\0\0\32\204\0\0\0\0\7\0\0\0\31\0\0\0K\0\0\0""0\0\0\0\25\0\0\0"
  1580.   "8\0\0\0\35\0\0\0\3\202\0\0\0\0\2\0\0\0\1\0\0\0\13\202\0\0\0""0\4\0\0"
  1581.   "\0\21\0\0\0F\0\0\0>\0\0\0\3\203\0\0\0\0\21\0\0\0""5\0\0\0E\0\0\0\23\0"
  1582.   "\0\0""7\0\0\0\37\0\0\0\2\0\0\0\20\0\0\0\36\0\0\0\40\0\0\0\31\0\0\0\6"
  1583.   "\0\0\0\7\0\0\0""2\0\0\0#\0\0\0)\0\0\0I\0\0\0\22\203\0\0\0\0\21\0\0\0"
  1584.   "\20\0\0\0\25\0\0\0\"\0\0\0""1\0\0\0\4\0\0\0\30\0\0\0\35\0\0\0\13\0\0"
  1585.   "\0\7\0\0\0\21\0\0\0\"\0\0\0\10\0\0\0\25\0\0\0""6\0\0\0\20\0\0\0\33\0"
  1586.   "\0\0\4\205\0\0\0\0\15\0\0\0\31\0\0\0\21\0\0\0\16\0\0\0\36\0\0\0\2\0\0"
  1587.   "\0\0\0\0\0\1\0\0\0\0\0\0\0\14\0\0\0\40\0\0\0\3\0\0\0\40\0\0\0\10\206"
  1588.   "\0\0\0\0\16***\21\210\210\210G\223\223\223LiiiL\204\204\204L\34=n\300"
  1589.   "\14""1i\361\12""0i\374\20""4j\342CXx}dddL\202\202\202LxxxG\40\40\40\21"
  1590.   "\205\0\0\0\0\2&&&\13\251\251\251F\202\374\374\374L\202\372\372\372L\5"
  1591.   "\"Cv\310Lf\217\226@]\211\245\12""0i\377\22""7n\353\202\365\365\365L\3"
  1592.   "\362\362\362L\226\226\226F\27\27\27\14\204\0\0\0\0\21,,,!\354\354\354"
  1593.   "L\355\355\355L\351\351\351L\346\346\346L\342\342\342L\335\335\335L\334"
  1594.   "\334\334L\210\227\255h\12""0i\377\21""6l\352\316\316\316L\313\313\313"
  1595.   "L\307\307\307L\314\314\314L\35\35\35$\0\0\0\1\202\0\0\0\0\14\0\0\0\1"
  1596.   "((('\357\357\357L\345\345\345L\341\341\341L\337\337\337L\333\333\333"
  1597.   "L\326\326\326L|\215\245l\20""5l\355\12""0i\374Sj\215\205\202\302\302"
  1598.   "\302L\4\314\314\314L\311\311\311L\33\33\33'\0\0\0\2\202\0\0\0\1\22\0"
  1599.   "\0\0\2&&&(\356\356\356L\342\342\342L\347\347\347L\346\346\346L\324GG"
  1600.   "L\337\337\337L\22""0g\351\12""0i\377^9Z\201<\341@L\324GGL<\341@L\321"
  1601.   "\321\321L\276\276\276L\27\27\27)\0\0\0\4\202\0\0\0\1\22\0\0\0\5$$$+\355"
  1602.   "\355\355L\345\345\345L\344\344\344L\340\340\340L\334\334\334L\331\331"
  1603.   "\331Law\227\177`u\226\177\316\316\316L\312\312\312L\306\306\306L\307"
  1604.   "\307\307L\313\313\313L\272\272\272L\24\24\24,\0\0\0\7\202\0\0\0\2\27"
  1605.   "\0\0\0\7\"\"\"-\354\354\354L\346\346\346L\342\342\342L\337\337\337L\333"
  1606.   "\333\333L\327\327\327LSk\217\212Qi\216\212\314\314\314L\310\310\310L"
  1607.   "\305\305\305L\301\301\301L\276\276\276L\271\271\271L\23\23\23/\0\0\0"
  1608.   "\10\0\0\0\2\0\0\0\1\0\0\0\10\40\40\40,\310\310\310K\202\274\274\274L"
  1609.   "\3\272\272\272L\271\271\271L\270\270\270L\202\12""0i\377\16\271\271\271"
  1610.   "L\270\270\270L\266\266\266L\265\265\265L\264\264\264L\231\231\231K\16"
  1611.   "\16\16""0\0\0\0\10\0\0\0\2\0\0\0\1\0\0\0\3\0\0\0\16\0\0\0!\0\0\0%\205"
  1612.   "\0\0\0&\205\0\0\0'\12\0\0\0&\0\0\0$\0\0\0\22\0\0\0\4\0\0\0\1\0\0\0\0"
  1613.   "\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\4\206\0\0\0\6\203\0\0\0\7\202\0\0\0\6"
  1614.   "\4\0\0\0\4\0\0\0\2\0\0\0\1\0\0\0\0"]
  1615.  
  1616. signal_xpm_barely = [
  1617. "20 20 10 1",
  1618. "     c None",
  1619. ".    c #C6C6C6",
  1620. "+    c #CCCCCC",
  1621. "@    c #DBDBDB",
  1622. "#    c #D3D3D3",
  1623. "$    c #A9B099",
  1624. "%    c #95A173",
  1625. "&    c #6B8428",
  1626. "*    c #B4B7AC",
  1627. "=    c #80924D",
  1628. "               .+++.",
  1629. "               +@@@+",
  1630. "               +@@@+",
  1631. "               +@@@+",
  1632. "               +@@@+",
  1633. "          .++++#@@@+",
  1634. "          +@@@@@@@@+",
  1635. "          +@@@@@@@@+",
  1636. "          +@@@@@@@@+",
  1637. "          +@@@@@@@@+",
  1638. "     $%%%%#@@@@@@@@+",
  1639. "     %&&&&@@@@@@@@@+",
  1640. "     %&&&&@@@@@@@@@+",
  1641. "     %&&&&@@@@@@@@@+",
  1642. "     %&&&&@@@@@@@@@+",
  1643. "*%%%%=&&&&@@@@@@@@@+",
  1644. "%&&&&&&&&&@@@@@@@@@+",
  1645. "%&&&&&&&&&@@@@@@@@@+",
  1646. "%&&&&&&&&&@@@@@@@@@+",
  1647. "*%%%%%%%%%+++++++++."
  1648. ]
  1649.  
  1650.  
  1651. signal_xpm_best = [
  1652. "20 20 6 1",
  1653. "     c None",
  1654. ".    c #9DAABF",
  1655. "+    c #7B96BF",
  1656. "@    c #386EBF",
  1657. "#    c #5982BF",
  1658. "$    c #AEB4BF",
  1659. "               .+++.",
  1660. "               +@@@+",
  1661. "               +@@@+",
  1662. "               +@@@+",
  1663. "               +@@@+",
  1664. "          .++++#@@@+",
  1665. "          +@@@@@@@@+",
  1666. "          +@@@@@@@@+",
  1667. "          +@@@@@@@@+",
  1668. "          +@@@@@@@@+",
  1669. "     .++++#@@@@@@@@+",
  1670. "     +@@@@@@@@@@@@@+",
  1671. "     +@@@@@@@@@@@@@+",
  1672. "     +@@@@@@@@@@@@@+",
  1673. "     +@@@@@@@@@@@@@+",
  1674. "$++++#@@@@@@@@@@@@@+",
  1675. "+@@@@@@@@@@@@@@@@@@+",
  1676. "+@@@@@@@@@@@@@@@@@@+",
  1677. "+@@@@@@@@@@@@@@@@@@+",
  1678. "$++++++++++++++++++."
  1679. ]
  1680.  
  1681. signal_xpm_none = [
  1682. "20 20 6 1",
  1683. "     c None",
  1684. ".    c #C6C6C6",
  1685. "+    c #CCCCCC",
  1686. "@    c #DBDBDB",
  1687. "#    c #D3D3D3",
  1688. "$    c #C2C2C2",
  1689. "               .+++.",
  1690. "               +@@@+",
  1691. "               +@@@+",
  1692. "               +@@@+",
  1693. "               +@@@+",
  1694. "          .++++#@@@+",
  1695. "          +@@@@@@@@+",
  1696. "          +@@@@@@@@+",
  1697. "          +@@@@@@@@+",
  1698. "          +@@@@@@@@+",
  1699. "     .++++#@@@@@@@@+",
  1700. "     +@@@@@@@@@@@@@+",
  1701. "     +@@@@@@@@@@@@@+",
  1702. "     +@@@@@@@@@@@@@+",
  1703. "     +@@@@@@@@@@@@@+",
  1704. "$++++#@@@@@@@@@@@@@+",
  1705. "+@@@@@@@@@@@@@@@@@@+",
  1706. "+@@@@@@@@@@@@@@@@@@+",
  1707. "+@@@@@@@@@@@@@@@@@@+",
  1708. "$++++++++++++++++++."
  1709. ]
  1710.  
  1711. signal_xpm_ok = [
  1712. "20 20 10 1",
  1713. "     c None",
  1714. ".    c #C6C6C6",
  1715. "+    c #CCCCCC",
  1716. "@    c #DBDBDB",
  1717. "#    c #A1A5B2",
  1718. "$    c #848DA5",
  1719. "%    c #D3D3D3",
  1720. "&    c #4A5B8C",
  1721. "*    c #677498",
  1722. "=    c #B0B2B8",
  1723. "               .+++.",
  1724. "               +@@@+",
  1725. "               +@@@+",
  1726. "               +@@@+",
  1727. "               +@@@+",
  1728. "          #$$$$%@@@+",
  1729. "          $&&&&@@@@+",
  1730. "          $&&&&@@@@+",
  1731. "          $&&&&@@@@+",
  1732. "          $&&&&@@@@+",
  1733. "     #$$$$*&&&&@@@@+",
  1734. "     $&&&&&&&&&@@@@+",
  1735. "     $&&&&&&&&&@@@@+",
  1736. "     $&&&&&&&&&@@@@+",
  1737. "     $&&&&&&&&&@@@@+",
  1738. "=$$$$*&&&&&&&&&@@@@+",
  1739. "$&&&&&&&&&&&&&&@@@@+",
  1740. "$&&&&&&&&&&&&&&@@@@+",
  1741. "$&&&&&&&&&&&&&&@@@@+",
  1742. "=$$$$$$$$$$$$$$++++."
  1743. ]
  1744.  
  1745.  
  1746. signal_xpm_low = [
  1747. "20 20 8 1",
  1748. "     c None",
  1749. ".    c #C6C6C6",
  1750. "+    c #CCCCCC",
  1751. "@    c #DBDBDB",
  1752. "#    c #D3D3D3",
  1753. "$    c #BFB0B5",
  1754. "%    c #C18799",
  1755. "&    c #C54F74",
  1756. "               .+++.",
  1757. "               +@@@+",
  1758. "               +@@@+",
  1759. "               +@@@+",
  1760. "               +@@@+",
  1761. "          .++++#@@@+",
  1762. "          +@@@@@@@@+",
  1763. "          +@@@@@@@@+",
  1764. "          +@@@@@@@@+",
  1765. "          +@@@@@@@@+",
  1766. "     .++++#@@@@@@@@+",
  1767. "     +@@@@@@@@@@@@@+",
  1768. "     +@@@@@@@@@@@@@+",
  1769. "     +@@@@@@@@@@@@@+",
  1770. "     +@@@@@@@@@@@@@+",
  1771. "$%%%%#@@@@@@@@@@@@@+",
  1772. "%&&&&@@@@@@@@@@@@@@+",
  1773. "%&&&&@@@@@@@@@@@@@@+",
  1774. "%&&&&@@@@@@@@@@@@@@+",
  1775. "$%%%%++++++++++++++."
  1776. ]
  1777. signal_none_pb    = None
  1778. signal_low_pb    = None
  1779. signal_barely_pb= None
  1780. signal_ok_pb    = None
  1781. signal_best_pb    = None
  1782. exit_flag        = False
  1783. current_ip        = ''
  1784. current_ssid    = ''
  1785. ####################################################################################################
  1786. # Make so we can be imported
  1787. if __name__ == "__main__":
  1788.     # Are we in configure mode?
  1789.     if len( sys.argv ) > 1 and ( sys.argv[1] == '--version' or sys.argv[1] == '-v' ):
  1790.         print "WiFi-Radar version %s" % WIFI_RADAR_VERSION
  1791.     elif len( sys.argv ) > 1 and ( sys.argv[1] == '--daemon' or sys.argv[1] == '-d' ):
  1792.         scanning_thread()
  1793.         connect_to_preferred()
  1794.     else:
  1795.         import gtk, gobject
  1796.         gtk.threads_init()
  1797.         configure()
  1798.